2015-10-17 54 views
5

Tôi đang sử dụng MongoDB để tìm kiếm các phần tử chứa danh sách các danh sách có ít nhất một mục trong danh sách khớp với tham số tìm kiếm.MongoDB tìm giá trị trong danh sách các danh sách

Đây là ví dụ về cấu trúc hiện tại của tôi.

{ 
    "Item 1":{ 
     "data":[ 
     ["green", 1] 
     ] 
    }, 
    "Item 2":{ 
     "data":[ 
     ["blue", 9], 
     ["green", 1] 
     ] 
    } 
} 

Tôi muốn tìm kiếm cho tất cả các mặt hàng có giá trị "xanh" trong danh sách dữ liệu.

Tôi hiện có này:

my_data.find({'data': {'$in': ['green']}}) 

tuy nhiên, không có kết quả được trả về.

+1

Điều này có thể giúp. http://stackoverflow.com/questions/17303833/mongodb-nested-array-query – lostintranslation

Trả lời

5

Bạn cần "đường dẫn trực tiếp" tới bất kỳ phần tử được truy vấn và "dữ liệu" nào không phải là "cấp cao nhất" của đường dẫn bạn cần tìm kiếm tại đây, thay vào đó là "Mục 1" hoặc "Mục 2 "trong tài liệu và" dữ liệu "là một phần tử phụ của điều đó.

Trường hợp cơ bản là sử dụng "dot notation" trong đó các phần tử gốc được "biết" ít nhất có thể tồn tại và cũng lưu ý rằng toán tử $in không cần thiết để khớp với một giá trị trong một mảng, vì MongoDB không quan tâm. Nhưng bạn sẽ cần một lồng nhau $elemMatch thay vì:

db.my_data.find({ 
    "$or": [ 
     { "Item 1.data": { 
      "$elemMatch": { 
       "$elemMatch": { "$eq": "green" } 
      } 
     }}, 
     { "Item 2.data": { 
      "$elemMatch": { 
       "$elemMatch": { "$eq": "green" } 
      } 
     }} 
    ] 
}) 

Không có "ký tự đại diện" cho phù hợp với một bộ phận của một con đường preceeding vì thế nó là cần thiết để nêu đường dẫn đầy đủ trong một điều kiện $or để tìm kiếm mỗi con đường có thể trong tài liệu.

Nếu viết ra tất cả các phím tiền tố có thể là không thực tế, sau đó chỉ cách tiếp cận khác của bạn đang sử dụng đánh giá JavaScript với $where để xác định logic cho phù hợp:

db.my_data.find(function() { 
    var doc = this; 
    delete doc._id; 

    var matched = false; 
    for (k in doc) { 
     matched = doc[k].data.some(function(el) { 
      return el.some(function(inner) { 
       return inner === "green"; 
      }); 
     }); 
     if (matched) break; 
    } 
    return matched; 
}) 

Hoặc một số biến thể của logic rằng để thực sự kiểm tra khả năng các phần tử có mảng "dữ liệu" chứa giá trị "xanh" của bạn. Nó không phải là một giải pháp tuyệt vời vì $where yêu cầu thực thi trên mỗi tài liệu để đánh giá điều kiện và do đó không thể sử dụng chỉ mục để lọc kết quả. Điều này có nghĩa là quét toàn bộ bộ sưu tập và về cơ bản là cách tiếp cận chậm nhất.

Cũng chỉ hiển thị "lối tắt shell" để viết rằng nếu không, nội dung function() được gửi dưới dạng "chuỗi" trong đối số $where cho trình điều khiển ngôn ngữ hoặc pymongo. được đánh giá trên máy chủ.

Tốt hơn là thay đổi tài liệu của bạn để luôn có đường dẫn nhất quán cho phần tử bạn muốn truy vấn. Chẳng hạn như:

{ 
    "items": [ 
     { "name": "Item 1", "data": [["green", 1]] }, 
     { "name": "Item 2", "data": [["blue", 9], ["green", 1]] } 
    ] 
} 

Sau đó, bạn chỉ có thể đưa ra câu hỏi đơn giản này:

db.my_data.find({ "items.data": { "$elemMatch": { "$elemMatch": { "$eq": "green" } } } }) 

Là "con đường" luôn là "items.data" này cho phép một condtion đơn chỉ dành riêng cho con đường đó để kiểm tra tất cả các yếu tố

+0

Cảm ơn bạn đã trả lời thực sự toàn diện. Đây là một sự trợ giúp rất lớn. – Gunther

Các vấn đề liên quan