Tìm tài liệu với mảng chứa giá trị cụ thể


499

Nếu tôi có lược đồ này ...

person = {
    name : String,
    favoriteFoods : Array
}

... Trong đó favoriteFoodsmảng được điền bằng chuỗi. Làm thế nào tôi có thể tìm thấy tất cả những người có "sushi" là thực phẩm yêu thích của họ bằng cách sử dụng cầy mangut?

Tôi đã hy vọng cho một cái gì đó dọc theo dòng:

PersonModel.find({ favoriteFoods : { $contains : "sushi" }, function(...) {...});

(Tôi biết rằng không có $containsmongodb, chỉ giải thích những gì tôi đang mong đợi để tìm thấy trước khi biết giải pháp)

Câu trả lời:


693

favouriteFoodsmột chuỗi đơn giản, bạn chỉ có thể truy vấn trường đó trực tiếp:

PersonModel.find({ favouriteFoods: "sushi" }, ...);

Nhưng tôi cũng khuyên bạn nên làm cho mảng chuỗi rõ ràng trong lược đồ của bạn:

person = {
    name : String,
    favouriteFoods : [String]
}

Các tài liệu liên quan có thể được tìm thấy ở đây: https://docs.mongodb.com/manual/tutorial/query-arrays/


19
Điều này cũng hoạt động nếu favouriteFoodslà:favouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
k88074

12
Là một người mới sử dụng Mongo đến từ RDBMS như MySQL, để thấy rằng các giải pháp như vậy hoạt động đơn giản mà không cần THAM GIA và các bảng bổ sung khiến tôi tự hỏi tại sao tôi không bắt đầu với Mongo sớm hơn. Nhưng điều đó không có nghĩa là DBMS vượt trội so với DBMS khác - nó phụ thuộc vào trường hợp sử dụng của bạn.
Irvin Lim

9
Đừng nhầm lẫn. Ngay cả khi đó là danh sách của dict, bạn vẫn có thể truy vấn nó theo cách này. Mẫu: PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
Aminah Nuraini

3
Điều gì xảy ra khi tôi muốn tìm một Mảng chứa ít nhất hai chuỗi?
Hàng không Wang Wang

151

Không có $containstoán tử trong mongodb.

Bạn có thể sử dụng câu trả lời từ JohnnyHK khi nó hoạt động. Sự tương tự gần nhất để chứa mongo đó là $in, sử dụng truy vấn này của bạn sẽ như sau:

PersonModel.find({ favouriteFoods: { "$in" : ["sushi"]} }, ...);

10
Điều này có đúng không? Không mongodb mong đợi một loạt các giá trị khi sử dụng $ in? như {name: {$ in: ["Paul", "Dave", "Larry", "Adam"]}}?
Ludwig Magnusson

38
Huh? Điều này là không cần thiết. $inđược sử dụng khi bạn có nhiều giá trị truy vấn và tài liệu cần khớp với một trong số chúng. Đối với điều ngược lại (đó là những gì câu hỏi này là về), câu trả lời của JohnnyHK là chính xác. Tôi sẽ downvote nhưng tôi đoán câu trả lời này có thể hữu ích cho những người khác kết thúc trên trang này.
MalcolmOcean

4
Nhưng điều này đã giúp tôi thực sự truy vấn với một số giá trị: D Rất cám ơn!
Alexandre Bour trước

11
Cảm ơn. Đây là những gì tôi thực sự đang tìm kiếm, cách để tìm kiếm nhiều giá trị:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
totymedli

@MalcolmOcean là chính xác, trong đó toán tử $ in là ngược lại, có một mảng là giá trị . Các lĩnh vực là một mảng là những gì các câu hỏi được hỏi về. Tuy nhiên, nếu cả trường và giá trị là mảng, thì cả câu trả lời này và câu trả lời của JohnnyHK đều có liên quan, nghĩa là bạn cần $ in.
tscizzle

88

Tôi cảm thấy như $allsẽ thích hợp hơn trong tình huống này. Nếu bạn đang tìm kiếm một người thích sushi, bạn làm:

PersonModel.find({ favoriteFood : { $all : ["sushi"] }, ...})

Như bạn có thể muốn lọc thêm tìm kiếm của mình, như vậy:

PersonModel.find({ favoriteFood : { $all : ["sushi", "bananas"] }, ...})

$ingiống như OR và $allthích AND. Kiểm tra điều này: https://docs.mongodb.com/manual/reference/operator/query/all/


Xin lỗi, đây là một câu trả lời không chính xác cho câu hỏi của tôi. Tôi không tìm kiếm một kết quả khớp chính xác mà chỉ tìm các mảng chứa ít nhất giá trị được chỉ định.
Ludwig Magnusson

18
Đây là một câu trả lời hoàn toàn hợp lệ cho câu hỏi của bạn! Đối với một giá trị, không có sự khác biệt trong việc sử dụng $ all hoặc $ in. Nếu bạn có một vài giá trị như "sushi", "chuối", $ tất cả đang tìm kiếm những người có "sushi" VÀ "chuối" trong mảng Thực phẩm yêu thích của họ, nếu sử dụng $ trong bạn sẽ có được những người có "sushi" HOẶC "chuối "Trong mảng thực phẩm yêu thích của họ.
Jodo

vâng, không có $ chứa nhưng $ tất cả là loại của nó
datdinhquoc

3
Câu trả lời tốt nhất.
Nikolay Tsenkov

65

Trong trường hợp mảng chứa các đối tượng, ví dụ if favouriteFoodslà một mảng các đối tượng sau:

{
  name: 'Sushi',
  type: 'Japanese'
}

bạn có thể sử dụng truy vấn sau:

PersonModel.find({"favouriteFoods.name": "Sushi"});

2
Đây dễ dàng là câu trả lời tốt nhất. Dễ sử dụng hơn nhiều khi bạn đang vội.
Uber Schnoz

Đây phải là câu trả lời được lựa chọn. Nếu bạn đang xử lý truy vấn một mảng các tài liệu lồng nhau trong MongoDB, thì đây là cách bạn làm điều đó. Không chắc nó có hiệu quả nhất không nhưng nếu đó là tất cả những gì bạn đang cố gắng thực hiện thì đây là tất cả những gì bạn cần.
Kyle L.

32

Trong trường hợp bạn cần tìm tài liệu có chứa các phần tử NULL bên trong một mảng các tài liệu phụ, tôi đã tìm thấy truy vấn này hoạt động khá tốt:

db.collection.find({"keyWithArray":{$elemMatch:{"$in":[null], "$exists":true}}})

Truy vấn này được lấy từ bài đăng này: mảng truy vấn MongoDb với các giá trị null

Đó là một phát hiện tuyệt vời và nó hoạt động tốt hơn nhiều so với phiên bản ban đầu và sai của riêng tôi (hóa ra chỉ hoạt động tốt đối với các mảng có một yếu tố):

.find({
    'MyArrayOfSubDocuments': { $not: { $size: 0 } },
    'MyArrayOfSubDocuments._id': { $exists: false }
})

3

Mặc dù đồng ý với find () là hiệu quả nhất trong usecase của bạn. Vẫn có $ khớp khung tổng hợp, để dễ dàng truy vấn một số lượng lớn các mục nhập và tạo ra số lượng kết quả thấp giữ giá trị cho bạn đặc biệt là để nhóm và tạo tệp mới.

  PersonModel.aggregate([
            { 
                 "$match": { 
                     $and : [{ 'favouriteFoods' : { $exists: true, $in: [ 'sushi']}}, ........ ]  }
             },
             { $project : {"_id": 0, "name" : 1} }
            ]);

không hoạt động với mongodb 4.2 .. vui lòng trả lời
vimmi

Bạn đang gặp lỗi gì, vui lòng cung cấp chi tiết?
Amitesh

3

Incase of lookup_food_array là mảng.

match_stage["favoriteFoods"] = {'$elemMatch': {'$in': lookup_food_array}}

Incase of lookup_food_array là chuỗi.

match_stage["favoriteFoods"] = {'$elemMatch': lookup_food_string}

1

Đối với Loopback3, tất cả các ví dụ đưa ra không hoạt động đối với tôi hoặc nhanh như sử dụng API REST. Nhưng nó đã giúp tôi tìm ra câu trả lời chính xác mà tôi cần.

{"where":{"arrayAttribute":{ "all" :[String]}}}


1
Bạn là một người bảo vệ cuộc sống, cảm ơn! Tài liệu đó ở đâu và tôi đã bỏ lỡ nó? Bạn có thể gửi liên kết xin vui lòng? Cảm ơn.
dùng2078023

-3

Nếu bạn muốn sử dụng một cái gì đó như toán tử "chứa" thông qua javascript, bạn luôn có thể sử dụng biểu thức Chính quy cho ...

ví dụ. Giả sử bạn muốn lấy một khách hàng có "Bartolomew" làm tên

async function getBartolomew() {
    const custStartWith_Bart = await Customers.find({name: /^Bart/ }); // Starts with Bart
    const custEndWith_lomew = await Customers.find({name: /lomew$/ }); // Ends with lomew
    const custContains_rtol = await Customers.find({name: /.*rtol.*/ }); // Contains rtol

    console.log(custStartWith_Bart);
    console.log(custEndWith_lomew);
    console.log(custContains_rtol);
}

-26

Tôi biết chủ đề này đã cũ, nhưng đối với những người trong tương lai có thể tự hỏi cùng một câu hỏi, một giải pháp cực kỳ kém hiệu quả khác có thể được thực hiện:

PersonModel.find({$where : 'this.favouriteFoods.indexOf("sushi") != -1'});

Điều này tránh tất cả các tối ưu hóa bởi MongoDB vì vậy không sử dụng trong mã sản xuất.


Vì tò mò, có lợi thế gì khi làm theo cách này không?
Ludwig Magnusson

5
Điều này là vô cùng không hiệu quả so với câu trả lời được chấp nhận; nó cắt ngang tất cả các tối ưu hóa mà Mongo đưa vào hậu trường để tìm kiếm thẳng như trong chấp nhận.
không mong muốn

1
Đây chính xác là câu trả lời tôi cần trong trường hợp của tôi! Cảm ơn "người dùng" :)
Vasyl Boroviak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.