Найти документ с массивом, содержащим определенное значение

если у меня есть эта схема...

person = {
    name : String,
    favoriteFoods : Array
}

... где favoriteFoods массив заполняется строками. Как я могу найти всех людей, у которых есть "суши" в качестве их любимой еды, используя мангуста?

Я надеялся на что-то вроде:

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

(Я знаю, что нет $contains в mongodb, просто объясняя, что я ожидал найти, прежде чем узнать решение)

9 ответов


As favouriteFoods - это простой массив строк, вы можете просто запросить, что поле напрямую:

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

но я бы также рекомендовал сделать строковый массив явным в вашей схеме:

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

нет $contains оператор в mongodb.

вы можете использовать ответ от JohnnyHK, как это работает. Ближайшая аналогия с contains, которую имеет монго, -$in, используя этот запрос будет выглядеть так:

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

мне кажется $all было бы более уместным в этой ситуации. Если вы ищете человека, который находится в суши вы делаете:

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

как вы можете хотеть фильтровать больше вашего поиска, например:

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

$in как и $all как и. Проверьте это : https://docs.mongodb.com/manual/reference/operator/query/all/


Если вам нужно найти документы, содержащие нулевые элементы внутри массива вложенных документов, я нашел этот запрос, который работает довольно хорошо:

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

этот запрос взят из этого поста: массив запросов MongoDb со значениями null

Это была отличная находка, и она работает намного лучше, чем мой собственный начальный и неправильно версия (которая отлично работала только для массивов с одним элементом):

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

В случае, если массив содержит объекты, например, если favouriteFoods представляет собой массив объектов следующего вида:

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

вы можете использовать следующий запрос:

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

для Loopback3 все приведенные примеры не работали для меня или так же быстро, как использование REST API. Но это помогло мне найти точный ответ.

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


хотя согласен с find () является наиболее эффективным в вашем usecase. Тем не менее существует $match of aggregation framework, чтобы облегчить запрос большого количества записей и генерировать небольшое количество результатов, которые имеют значение для вас, особенно для группировки и создания новых файлов.

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

Если вы хотите использовать что-то вроде оператора "contains" через javascript, вы всегда можете использовать для этого регулярное выражение...

например. Скажем, вы хотите получить клиента, имеющего" Bartolomew " как имя

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);
}

Я знаю, что эта тема старая, но для будущих людей, которые могли бы задаться тем же вопросом, другим невероятно неэффективным решением может быть:

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

это позволяет избежать всех оптимизаций MongoDB, поэтому не используйте в производственном коде.