web-dev-qa-db-fra.com

Rechercher plusieurs champs pour plusieurs valeurs dans MongoDB

J'ai une collection MongoDB dans laquelle une chaîne particulière peut apparaître dans plusieurs champs:

{"_id":1, "field1":"foo","field2":"bar","field3":"baz", "otherfield":"stuff"},
{"_id":2, "field1": "bar", "field2": "baz", "field3": "foo", "otherfield":"morestuff"},
{"_id":3, "field1": "baz", "field2": "foo", "field3": "bar", "otherfield":"you get the idea"}

J'ai besoin d'interroger pour obtenir tous les enregistrements où l'un des champs est égal à une valeur d'un tableau ... si j'ai ["foo","bar"], je dois le faire correspondre si l'une de ces chaînes est dans le champ1 ou field2 (mais pas n'importe quel autre champ).

Évidemment, je peux le faire avec une série de requêtes multiples

db.collection.find({"field1":{"$in":["foo","bar"]}})db.collection.find({"field2":{"$in":["foo","bar"]}})

etc., et j'ai également fait une très grosse requête $ ou une requête qui les concatène toutes ensemble, mais cela semble beaucoup trop inefficace (ma collection réelle doit correspondre à l'une des 15 chaînes pouvant se produire dans l'un des 9 champs) ... mais je suis encore nouveau dans nos DB et je ne suis pas sûr du meilleur paradigme que je devrais utiliser ici. Toute aide est grandement appréciée.

13
jlmcdonald

Nous avons trouvé une autre réponse en parcourant la documentation qui semble frapper des points noirs: les index de texte.

db.collection.ensureIndex({"field1":"text","field2":"text"})
db.records.runCommand("text",{search:"foo bar"})

Lorsque j'exécute ma requête avec beaucoup plus de chaînes et de champs (et environ 100 000 enregistrements), l'approche $or/$in prend 620 millisecondes, tandis que l'index de texte prend 131 millisecondes. Le seul inconvénient est qu’elle renvoie un type de document différent; heureusement, les documents réels sont un paramètre de chaque objet du résultat. 

Merci à ceux qui ont pris le temps de faire des suggestions.

4
jlmcdonald

essayer 

db.collection.find(
    // Find documents matching any of these values
    {$or:[
        {"field1":{"$in":["foo","bar"]}},
        {"field2":{"$in":["foo","bar"]}}
    ]}
)

se référer également à cette question

19
a14m

Je voudrais collecter tous les champs pertinents dans un champ (c'est-à-dire collected) en ajoutant leurs valeurs comme 

"foo:field1", 
"bar:field2", 
"baz:field3",  
"stuff:otherfield", 
"bar:field1", 
"baz:field2"
...

dans ce domaine.

Si vous recherchez bar existant dans n’importe quel champ, vous pouvez utiliser:

db.collection.find( { collected: { $regex: "^bar" } }, ... );

Votre exemple dans la question ressemblerait à ceci:

db.collection.find( collected: { { $all: [ "foo:field1", "foo:field2", "bar:field1", "bar:field2" ] } }, ... ); 
0
heinob