web-dev-qa-db-fra.com

Requête de tableau imbriqué MongoDB

J'ai posé cette question en tant que commentaire sur ne autre question, et j'ai également posté une question sur mongodb-user. Jusqu'à présent, je n'ai pas répondu. Je me pose donc une question distincte.

documentation indique:

Si le champ contient un tableau, l'opérateur $ in sélectionne les documents dont le champ contient un tableau qui contient au moins un élément qui correspond à une valeur du tableau spécifié (par exemple, etc.)

J'utilise:

mongod --version:
db version v2.2.2, pdfile version 4.5
Thu May 30 12:19:12 git version: d1b43b61a5308c4ad0679d34b262c5af9d664267

mongo --version:
MongoDB Shell version: 2.0.4

Dans MongoDB Shell:

db.nested.insert({'level1': {'level2': [['item00', 'item01'], ['item10', 'item11']]}})

Voici une liste de requêtes qui devraient fonctionner selon la documentation et les résultats qu'elles produisent:

Pourquoi ça ne marche pas?

> db.nested.findOne({'level1.level2.0': 'item00'})
null

Pourquoi ai-je besoin de $ all?

> db.nested.findOne({'level1.level2.0': {'$all': ['item00']}})
{
    "_id" : ObjectId("51a7a4c0909dfd8872f52ed7"),
    "level1" : {
        "level2" : [
            [
                "item00",
                "item01"
            ],
            [
                "item10",
                "item11"
            ]
        ]
    }
}

Au moins l'un des éléments suivants devrait fonctionner, non?

> db.nested.findOne({'level1.level2.0': {'$in': ['item00']}})
null

> db.nested.findOne({'level1.level2': {'$in': ['item00']}})
null

Des idées? Nous envisageons d'abandonner MongoDB si la syntaxe de requête ne fonctionne pas comme annoncé.

Merci!

40
dgorur

Utilisez imbriqué elemMatch pour rechercher des niveaux imbriqués dans des tableaux.

Détails Interrogation d'un tableau de tableaux dans MongoDB

8
dgorur

Après avoir exécuté quelques requêtes, je suis arrivé à la conclusion que $ in ne fonctionne pas pour un tableau de tableaux.

Vous pouvez utiliser $elemMatch à la place et cela fonctionnera, mais il est frustrant que la documentation de MongoDB ne le prévienne pas.

J'ai créé ce document:

{
      "_id": "51cb12857124a215940cf2d4",
      "level1": [
        [
          "item00",
          "item01"
        ],
        [
          "item10",
          "item11"
        ]
      ],
      "items": [
        "item20",
        "item21"
      ]
}

Notez que le champ "items" est un tableau de chaînes et cette requête fonctionne parfaitement:

db.nested.findOne({"items":{"$in":["item20"]} })

Maintenant, "level1.0" est également un tableau de chaînes, la seule différence est qu'il se trouve dans un autre tableau. Cette requête devrait fonctionner mais n'est pas:

db.nested.findOne({"level1.0":{"$in":["item00"]} })

La seule façon d'obtenir le résultat est d'utiliser $ elemMatch:

db.nested.findOne({"level1":{"$elemMatch":{"$in":['item00']}} })

Alors $elemMatch résout le problème, mais la vraie solution est de mettre à jour la documentation de MongoDB pour indiquer que $in ne fonctionne pas pour les tableaux de tableaux. Vous devriez peut-être soumettre une demande à 10gen.

39
AntonioOtero

Réponse courte: $ in est pour un champ à valeur unique et $ all est pour les tableaux.

Premièrement, db.nested.findOne({'level1.level2.0': 'item00'}) ne fonctionne pas car level1.level2.0 contient un tableau et vous essayez de le comparer avec une seule valeur.

Maintenant, db.nested.findOne({'level1.level2.0': {'$in': ['item00']}}) ne fonctionne pas non plus pour une raison similaire. $ in sert à comparer un champ avec une seule valeur (vous avez un tableau) avec plusieurs valeurs dans un tableau (spécifié dans la requête). $ in dit: donnez-moi les documents qui ont ce champ dont la valeur est incluse dans ce tableau.

$ all fonctionne parce qu'il dit: donnez-moi les documents qui ont ce champ avec plusieurs valeurs et toutes les valeurs de ce tableau (dans la requête) sont incluses dans ce champ. (édité)

Cela peut être difficile à obtenir, mais regardez ce que la documentation dit pour chacun:

$ all sélectionne les documents où le champ contient un tableau et contient tous les éléments(e.g. <value>, <value1>, etc.) dans le tableau.

$ in sélectionne les documents où la valeur du champ est égale à toute valeur dans le tableau spécifié (e.g. <value1>, <value2>, etc.)

J'espère que ça aide

5
AntonioOtero