web-dev-qa-db-fra.com

Rechercher un document avec un tableau contenant une valeur spécifique

Si j'ai ce schéma ...

person = {
    name : String,
    favoriteFoods : Array
}

... où le tableau favoriteFoods est rempli de chaînes. Comment trouver toutes les personnes qui ont le "sushi" comme aliment préféré à base de mangouste?

J'espérais quelque chose du genre:

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

(Je sais qu'il n'y a pas de $contains dans mongodb, expliquant simplement ce que je m'attendais à trouver avant de connaître la solution)

375
Ludwig Magnusson

Comme favouriteFoods est un simple tableau de chaînes, vous pouvez simplement interroger ce champ directement:

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

Mais je vous recommanderais également de rendre le tableau de chaînes explicite dans votre schéma:

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

Il n'y a pas d'opérateur $contains dans mongodb.

Vous pouvez utiliser la réponse de JohnnyHK comme cela fonctionne. L'analogie la plus proche de contient que mongo est $in, avec ceci votre requête ressemblerait à ceci:

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

Je pense que $all serait plus approprié dans cette situation. Si vous recherchez une personne qui aime le sushi, vous le faites:

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

Comme vous voudrez peut-être filtrer davantage votre recherche, comme ceci:

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

$in est comme OR et $all comme AND. Vérifiez ceci: https://docs.mongodb.com/manual/reference/operator/query/all/

57
Pobe

Si le tableau contient des objets, par exemple, si favouriteFoods est un tableau d'objets du type suivant:

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

vous pouvez utiliser la requête suivante:

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

Au cas où vous auriez besoin de trouver des documents contenant des éléments NULL dans un tableau de sous-documents, j'ai trouvé cette requête qui fonctionne plutôt bien:

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

Cette requête provient de cet article: Tableau de requêtes MongoDb avec des valeurs NULL

C'était une excellente découverte et cela fonctionne beaucoup mieux que ma propre version initiale et fausse (qui s'est avérée ne fonctionner correctement que pour les tableaux contenant un seul élément):

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

Bien qu'accepter, find () est le plus efficace dans votre cas d'utilisation. Néanmoins, il existe toujours une correspondance de structure d'agrégation pour faciliter l'interrogation d'un grand nombre d'entrées et générer un faible nombre de résultats qui ont une valeur pour vous, en particulier pour le regroupement et la création de nouveaux fichiers.

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

Pour Loopback3, tous les exemples donnés ne fonctionnaient pas pour moi ou aussi rapidement que l’utilisation de l’API REST de toute façon. Mais cela m'a aidé à trouver la réponse exacte dont j'avais besoin.

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

1
Mark Ryan Orosa

Si vous souhaitez utiliser quelque chose comme un opérateur "contient" via javascript, vous pouvez toujours utiliser une expression régulière pour cela ...

par exemple . Disons que vous voulez récupérer un client ayant pour nom "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);
}
0
Alingenomen

Le cas où lookup_food_array est un tableau.

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

Si cas de lookup_food_array est une chaîne.

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