2011-07-22 11 views
34

Revisé la documentación de MongoDB y busqué en Google esta pregunta, pero no pude encontrar una respuesta adecuada. Entonces, esto es lo que estoy buscando. Supongamos que tengo una colección de elementos de este tipo:Buscando el valor de cualquier campo en MongoDB sin nombrarlo explícitamente

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

Lo que me gustaría lograr es encontrar un elemento mediante la búsqueda en todos (tal vez a excepción de un número finito de ;-)) Campos. En otras palabras: dada una consulta, NO sé en qué campo se debe encontrar la consulta.

En mi forma de pensar algo como esto

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

me daría el elemento de ejemplo.

Gracias por su ayuda.

+0

Por lo tanto, lo que su necesidad es algo así como una búsqueda de texto completo , que no está implementado de forma nativa en mongodb, también ver: http://www.mongodb.org/display/DOCS/Full+Text+Search+in+Mongo – asaaki

+0

No creo que sea una pregunta de búsqueda de texto. Es consulta por valor. Ambos comparten el hecho de que no hay soporte nativo para él en mongo;) –

+1

@asaaki: mientras tanto, Mongo ha implementado [búsqueda de texto completo] (http://docs.mongodb.org/manual/core/index- texto/). Borremos nuestros comentarios –

Respuesta

21

Esto no es posible sin la inspección individual de documentos en la aplicación o mediante la ejecución del código del lado del servidor. Considere cambiar su esquema para:

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

Obviamente, esto tiene algunos inconvenientes (el rendimiento y el esquema contaminado en su mayoría) pero permitirá que lo que necesita a través de:

db.things.find({'params.value':"bar"}) 
+4

¿Cómo funciona la respuesta objetivamente correcta con dos votos a favor? –

+0

¿Cómo puedo ordenar por un campo particular con este esquema? Me refiero a algo así como .sort ({foo: 1}) en el de OP. – runTarm

+1

No es así. find ({'params.field': "foo"}). sort ({'params.value': 1}) no es equivalente debido a la manera en que funciona la ordenación de matrices. –

2

Usted puede hacerlo con una función recursiva:

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

Para realizar una búsqueda de texto, debe crear índices de texto para su colección. Para obtener más información, mira la documentación mongo: indexes text

10

This answer a una pregunta similar tiene su solución, que voy a repetir aquí para completar. Puede usar el operador $where para ejecutar JavaScript arbitrario en los servidores MongoDB, con la advertencia de que esto será mucho más lento que casi cualquier otro tipo de consulta. Por su ejemplo, sería:

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

hacer una búsqueda de texto en todos los campos, primero debe crear un índice de texto en todos los campos.

como mongodb documentation indica, "Para permitir la búsqueda de texto en todos los campos con contenido de cadena, use el especificador de comodín ($ **) para indexar todos los campos que contienen contenido de cadena."

si está trabajando dentro del shell mongo (que ejecuta desde la línea de comandos llamando a 'mongo'), puede hacerlo con este comando, donde 'colección' es el nombre de la colección en el archivo db quiere usar.

db.collection.createIndex({ "$**": "text" },{ name: "TextIndex" })

el segundo objeto, es decir {name:"TextIndex"}, es opcional ... que en realidad no necesita dar el índice de un nombre, ya que sólo puede haber un único índice de texto en cada colección (a la vez. ..puedes soltar índices y crear nuevos si quieres).

una vez que haya creado un índice de texto en todos los campos, se puede hacer una búsqueda de texto simple con el siguiente objeto de consulta: { $text : { $search: <your string> } }

lo tanto, si usted está escribiendo una función de JavaScript que podría hacer algo como:

var cursor = db.collection(<collection_name>).find({ $text: { $search: <your string> } });

para obtener más información sobre las distintas formas de controlar la búsqueda, consulte la documentación mongodb en la búsqueda de texto here

+0

Si la cadena se ha escapado de una palabra que rodea a la palabra, la búsqueda se convierte en una búsqueda 'y' en lugar de 'o' buscar. {$ Text: {$ search: "\" jim \ "\" hábito \ " "}} encuentra todos los registros con 'jim' y 'hábito' en el índice de texto. –

0

Usar $where es lo mismo que hacer una exploración de tabla completa y no puede usar los índices. Asimismo, no podía conseguir que funcione, sin embargo, no encontramos que esto funcionaba (que también hace el equivalente de un escaneo completo de tabla):

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

donde /needle/ es una expresión regular para encontrar en el valor de doc[key]

5

Lamentablemente, ninguna de las respuestas anteriores aborda el hecho de que mongo puede contener valores anidados en matrices u objetos anidados.

ESTE ES EL CORRECTO CONSULTA:

{$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") 
}} 

Desde llamando typeof en matriz o objeto anidado volverá 'objeto' esto significa que la consulta se iterar sobre todos los elementos anidados y tendrá iterar a través de todos entonces hasta el Se encontrará la clave con valor.

Puede verificar las respuestas anteriores con un valor anidado y los resultados estarán lejos de ser deseados.

Stringifying todo el objeto es mucho menos eficaz, ya que tiene que recorrer todos los sectores de memoria uno por uno tratando de hacer coincidir. Y crea una copia del objeto como una cadena en la memoria RAM (tanto ineficaz puesto consulta utiliza más memoria RAM y lento desde contexto función ya tiene un objeto cargado)

+0

podemos reescribir if (obj [field] == value) like - if (typeof obj [field] == 'string' && obj [campo] .contains (/ value /)). Proporciona resultados de búsqueda más precisos –

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

db.collection_name.find({'foo':"bar"}) 
+0

Esto no es lo que solicitó OP. La pregunta era cómo encontrar elementos sin especificar el nombre del campo. – user2223059

Cuestiones relacionadas