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

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

person = {
    name : String,
    favoriteFoods : Array
}

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

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

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

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

Ответ 1

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

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

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

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

Соответствующую документацию можно найти здесь: https://docs.mongodb.com/manual/tutorial/query-arrays/

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

Если массив содержит объекты, например, если favouriteFoods - это массив объектов следующего типа:

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

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

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

Ответ 5

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

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

Этот запрос взят из этого сообщения: массив запросов MongoDb с нулевыми значениями

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

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

Incase of lookup_food_array это массив.

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

Incase of lookup_food_array это строка.

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

Ответ 9

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

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

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

Ответ 10

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

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

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