web-dev-qa-db-fra.com

Recherche de la valeur d'un champ dans MongoDB sans le nommer explicitement

J'ai parcouru la documentation de MongoDB et cherché sur Google cette question, mais je n'ai pas vraiment trouvé de réponse satisfaisante. Alors, voici ce que je cherche. Supposons que j'ai une collection avec des éléments comme celui-ci:

{
   "foo" : "bar",
   "test" : "test",
   "key" : "value",
}

Ce que j'aimerais réaliser, c'est trouver un élément en cherchant dans tous les domaines (sauf peut-être pour beaucoup ;-)) En d'autres termes: étant donné une requête, je ne sais pas dans quel champ la requête doit être trouvée.

Dans ma pensée, quelque chose comme ça 

db.things.find({_ANY_ : "bar"}) 

me donnerait l'exemple de l'élément.

Merci de votre aide.

41
Max L.

Cela n'est pas possible sans une inspection individuelle des documents côté application ou via l'exécution de code côté serveur. Pensez à changer votre schéma pour:

{params:[{field:"foo", value:"bar"}, {field:"test", value:"test"}, {field:"key", value:"value"}]}

Cela a évidemment quelques inconvénients (performances et schémas généralement corrigés), mais vous permettra de répondre à vos besoins avec:

db.things.find({'params.value':"bar"})
25
Remon van Vliet

Cette réponse à une question similaire a votre solution, que je vais répéter ici pour être complet. Vous pouvez utiliser l'opérateur $where pour exécuter du JavaScript arbitraire sur le (s) serveur (s) MongoDB, en précisant que cela sera beaucoup plus lent que presque tout autre type de requête. Pour votre exemple, ce serait:

db.things.find({$where: function() {
    for (var key in this) {
        if (this[key] === "bar") {
            return true;
        }
        return false;
    }
}});
17
Tom Panning

Malheureusement, aucune des réponses précédentes n'aborde le fait que mongo peut contenir des valeurs imbriquées dans des tableaux ou des objets imbriqués.

CECI IS LA QUESTION CORRECTE:

{$where: function() {
    var deepIterate = function  (obj, value) {
        for (var field in obj) {
            if (obj[field] == value){
                return true;
            }
            var found = false;
            if ( typeof obj[field] === 'object') {
                found = deepIterate(obj[field], value)
                if (found) { return true; }
            }
        }
        return false;
    };
    return deepIterate(this, "573c79aef4ef4b9a9523028f")
}}

Comme l'appel de typeof sur un tableau ou un objet imbriqué retournera 'objet', cela signifie que la requête itérera sur tous les éléments imbriqués et itérera tout au long de cette opération jusqu'à ce que la clé avec la valeur soit trouvée.

Vous pouvez vérifier les réponses précédentes avec une valeur imbriquée et les résultats seront loin d'être souhaités.

Le fichage de l’ensemble de l’objet est beaucoup moins performant, car il doit parcourir tous les secteurs de la mémoire un par un pour essayer de les faire correspondre. Et crée une copie de l'objet sous forme de chaîne dans la mémoire RAM (les deux sont inefficaces car la requête utilise plus de mémoire vive et sont lents puisque le contexte de la fonction a déjà un objet chargé)

13
twboc

Pour effectuer une recherche de texte, vous devez créer des index de texte pour votre collection ..__ Pour plus d'informations, consultez la documentation de mongo: indexes text

2
Salim Hamidi

Vous pouvez le faire avec une fonction récursive:

var recursiveSearch = function(query) {
    db.test_insert.find().forEach(function(items) {
        var i = 0;
        var recursiveFunc = function(itemsArray, itemKey) {
            var itemValue = itemsArray[itemKey];
            if(itemValue === query) { 
                printjson(items);
            }       

            if(typeof itemValue === "object") {
                Object.keys(itemValue).forEach(function(itemValueKey) {
                    recursiveFunc(itemValue, itemValueKey);
                });
            }
        };
        Object.keys(items).forEach(function(item){
            recursiveFunc(items, item);
        });
    });
};

recursiveSearch('your string');
2
RoXuS

Utiliser $ où revient à effectuer une analyse complète de la table et ne peut pas utiliser les index. Je ne pouvais pas non plus le faire fonctionner, mais j’ai trouvé que cela fonctionnait (cela équivaut également à un balayage complet de la table):

db.collection.find().forEach(function(doc){
for (var key in doc) {
    if ( /needle/.test(doc[key]) )
        printjson(doc);
    }
});

/needle/ est une expression régulière à trouver dans la valeur de doc[key]

1
Waddles