2012-02-12 13 views
7

Recientemente he querido filtrar los registros que contienen un determinado conjunto de palabras clave en MongoDB, por ejemplo: Tengo cinco registros que contienen palabras clave matriz:mongodb -cómo buscar registros que contengan cierta gama palabras clave

{a:[1,2]} 
{a:[1,3,8]} 
{a:[1,2,5]} 
{a:[3,5,1]} 
{a:[4,5]} 

Si me entrada de la matriz [1,2,3,5] para la búsqueda, entonces yo quiero llegar:

{a:[1,2]} 
{a:[1,2,5]} 
{a:[3,5,1]} 

Cada uno de ellos es un conjunto de sub [1,2,3,5].

¿Alguna idea?

No utilice una cláusula where (cuando sea posible). ¡Gracias!

+0

Le gusta tener que escribir un filtro personalizado para esto en js, y luego usarlo como parte de la consulta. http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-JavascriptExpressionsand%7B%7B%24where%7D%7D – Travis

Respuesta

8

Es simple de hacer en mongodb, pero la parte más difícil es preparar los datos para la consulta. Voy a explicar que, en oder

parte simple

Puede utilizar $in para encontrar los elementos coincidentes en una matriz. Tratemos

db.coll.find({a:{$in:[1,2,3,5]}) 

y el resultado es

{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] } 
{ "_id" : ObjectId("4f37c42439ed13aa728e9efc"), "a" : [ 1, 3, 8 ] } 
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] } 
{ "_id" : ObjectId("4f37c43439ed13aa728e9efe"), "a" : [ 3, 5, 1 ] } 
{ "_id" : ObjectId("4f37c43e39ed13aa728e9eff"), "a" : [ 4, 5 ] } 

ohh, no es el resultado que esperábamos. Sí porque $ a cambio de un elemento si se encuentra algún elemento coincidente (no necesariamente todos).

Así que podemos solucionar esto pasando los elementos de matriz exactos a $ in, por ejemplo, si queremos encontrar los elementos que coincidan con estas matrices exactas {a: [1,2]} {a: [1,2,5 ]} y {a: [4,5,6]}

db.coll.find({a:{$in:[[1,2],[1,2,5],[4,5,6]]}}) 

usted recibirá

{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] } 
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] } 

Eso es todo

parte más difícil

La parte más difícil es formar toda la combinación posible de su matriz de entrada [1,2,3,5]. Necesita encontrar una forma de obtener toda la combinación de la matriz fuente (de su cliente) y pasarla a $ in.

Por ejemplo, este JS method le dará todas las combinaciones de la matriz dada

var combine = function(a) { 
    var fn = function(n, src, got, all) { 
    if (n == 0) { 
     if (got.length > 0) { 
     all[all.length] = got; 
     } 
     return; 
    } 
    for (var j = 0; j < src.length; j++) { 
     fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all); 
    } 
    return; 
    } 
    var all = []; 
    for (var i=0; i < a.length; i++) { 
    fn(i, a, [], all); 
    } 
    all.push(a); 
    return all; 
} 

>> arr= combine([1,2,3,5]) 

le dará

[ 
    [ 
     1 
    ], 
    [ 
     2 
    ], 
    [ 
     3 
    ], 
    [ 
     5 
    ], 
    [ 
     1, 
     2 
    ], 
    [ 
     1, 
     3 
    ], 
    [ 
     1, 
     5 
    ], 
    [ 
     2, 
     3 
    ], 
    [ 
     2, 
     5 
    ], 
    [ 
     3, 
     5 
    ], 
    [ 
     1, 
     2, 
     3 
    ], 
    [ 
     1, 
     2, 
     5 
    ], 
    [ 
     1, 
     3, 
     5 
    ], 
    [ 
     2, 
     3, 
     5 
    ], 
    [ 
     1, 
     2, 
     3, 
     5 
    ] 
] 

y se puede pasar este arr a $ en encontrar toda la macthing elementos

 db.coll.find({a:{$in:arr}}) 

le dará

{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] } 
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] } 

¡Espere! Todavía no devuelve los dos elementos restantes.

Porque echa un buen vistazo al arr, solo encuentra la combinación. devuelve [1,3,5] pero los datos en el documento son [3,5,1]. Así que está claro que $in verifica los artículos en el orden dado (¡extraño!).

Así que ahora entiendes que es realmente difícil comparar la consulta mongodb !. Puede cambiar el anterior código JS de combinación anterior para encontrar la permutación posible de cada combinación y pasarla a mongodb $in. Ese es el truco.

Como no mencionó ninguna opción de idioma, es difícil recomendar un código de permutación. Pero puedes encontrar muchos enfoques diferentes en Stackoverflow o en Google.

0

Si he entendido bien, se desea volver sólo los objetos cuya todos los valores de la propiedad a están en el argumento hallazgo matriz.

Siguiendo la sugerencia de Travis en los comentarios, debe seguir estos pasos:

  1. Definir una función JS para lograr sus deseos (ya que no hay forma nativa a hacer eso en MongoDB);
  2. Guarde la función en el servidor;
  3. Utilice la función dentro de $where.

Si definir su función para utilizar sólo a esa propiedad específica (a, en este caso), es posible que desee omitir el paso 2. Sin embargo, ya que puede ser una función útil para otras propiedades de otros documentos, me definió una función más genérica, que debe guardarse en el servidor para ser utilizada AFAIK (también soy nuevo en Mongo).

continuación no son mis pruebas en la consola mongo:

<--! language: lang-js --> 

// step 1: defining the function for your specific search 
only = function(property, values) { 
    for(var i in property) if (values.indexOf(property[i]) < 0) return false 
    return true 
} 

// step 2: saving it on the server 
db.system.js.save({ _id : 'only', value : only }) 

// step 3: using the function with $where 
db.coll.find({$where: "only(this.a, [1,2,3,5])"}) 

Con los 5 objetos que nos ha facilitado sobre la cuestión, se obtiene:

{ "_id" : ObjectId("4f3838f85594f902212eb532"), "a" : [ 1, 2 ] } 
{ "_id" : ObjectId("4f3839075594f902212eb534"), "a" : [ 1, 2, 5 ] } 
{ "_id" : ObjectId("4f38390e5594f902212eb535"), "a" : [ 3, 5, 1 ] } 

La desventaja es el rendimiento. See more.

Cuestiones relacionadas