2012-03-27 148 views
9

Quiero hacer una consulta eficiente en MongoDb para encontrar todos los usuarios que tienen sus userids listados en un grupo de usuarios. Idealmente, quiero hacer esto como una sola solicitud a Mongodb. Lo que deseo corresponde a selecciones anidadas en SQL. He intentado esto en la consola mongo:Cómo hacer consultas anidadas en MongoDb que funcionan como consultas de selección Sql anidadas

db.user.save({_id:"u1", Name:"u1 name"}); 
db.user.save({_id:"u2", Name:"u1 name"}); 
db.user.save({_id:"u3", Name:"u3 name"}); 
db.usergroup.save({_id:"g1", Users: ["u2","u3"]}); 

Ahora aquí es la de selección que quiero hacer, pero sin codificar el [ "U2", "U3"] matriz:

db.user.find({_id:{$in:["u2","u3"]}}).forEach(printjson); 

Este funciona bien y devuelve los objetos de usuario para u2 y u3.

Ahora la pregunta es cómo obtener la matriz de ID de usuario en el operador $ in extraída con una consulta para que toda la consulta se pueda realizar con una única solicitud.

Una "consulta anidada" como esto no funciona:

db.user.find({_id:{$in:db.usergroup.find({_id:"g1"},{_id:0,Users:1})}}).forEach(printjson); 

da este error: Mar Mar 27 de 6:17:41 excepción no detectada: error: { "$ err": "consulta no válida" , "código": 12580} no se pudo cargar: mongoNestedSelect.js

1) ¿es esto posible en mongodb y cómo?

2) ¿cómo hacer esto con el controlador C# oficial?

Respuesta

5

La respuesta a estas preguntas en MongoDB a menudo es desnormalizar sus datos. Si solo necesita una lista de los usuarios en el grupo, puede almacenar el ID de usuario y el nombre de usuario en el documento del grupo. De alguna manera, usted estructura su base de datos de acuerdo con el resultado que desea ver en la pantalla en lugar de tratar de ponerlo en un formato normalizado.

Claramente eso solo funcionaría si su lista de grupos de usuarios (con nombres) puede caber en un solo documento, pero su enfoque actual también tiene algunas limitaciones con respecto al tamaño máximo de un grupo.

Otro enfoque sería almacenar los grupos a los que pertenece un usuario en una matriz en cada documento 'Usuario'. Agregue un índice en ese campo de matriz y ahora puede buscar usuarios por grupo. Dado que es probable que un usuario pertenezca a menos grupos que miembros en un grupo, este puede ser el mejor enfoque aquí.

db.user.save({_id:"u1", name:"u1 name", groups:[{_id:"g1", name:"Group One"}, ...]}); 

De nuevo es posible almacenar el nombre del grupo con su _id para que pueda visualizar inmediatamente la lista de grupos pertenece un usuario con una sola ida y vuelta. Por supuesto, si permite que cambie el nombre de un grupo, deberá iniciar una tarea en segundo plano para ir a reparar todas estas copias del nombre.

También usaría el generador de id MongoDB integrado en lugar del suyo, tiene muchas propiedades deseables.

+0

ok gracias. Entonces, ¿las "consultas anidadas reales" no son posibles en MongoDB ?. Y sí, estoy de acuerdo con su comentario sobre ObjectIds, pero acabo de utilizar cadenas en este ejemplo para mantener las cosas simples. – ssn

+0

Correcto, sin consultas anidadas, sus datos deben estructurarse para que pueda obtener lo que desea con un único (o un número mínimo) de solicitudes a la base de datos. –

5

función

function bbb(){ 
    var org_ids = new Array(); 
    var orgs = 
     db.orgTreeNode.find({ancestors:"ca5cd344-ba47-4601-a07b-ea2c684bfb4e"},{"_id":1}); 
    orgs.forEach(function(org){ 
     org_ids.push(org._id); 
    }) 

    return db.user.find({"org":{$in:org_ids}}).skip(300).limit(10); 
} 

ejecutar la función

bbb() 
1

definir Si se puede activar para conseguir que ans--

db.users.find({ 
    _id: { 
     $in: db.logs.find({ 
      loggedbyuser: { 
       $ne: ObjectId("569f9d093447ee781ca80b52") 
      }, 
      logtype: "marketfetched", 
      "logcreated": { 
       $gt: new ISODate("2016-02-06T00:00:00.871Z") 
      } 
     }, { 
      loggedbyuser: 1, 
      _id: 0 
     }).sort({ 
      'logcreated': -1 
     }).map(function(like) { 
      return like.loggedbyuser; 
     }) 
    } 
}).map(function(like) { 
    return like.fullname; 
}); 
+1

El op está pidiendo una consulta anidada similar a SQL que se ejecuta en un solo paso dentro de la base de datos. Solo está obteniendo los resultados de la consulta "anidada" y la envía de nuevo por todo el cable. –

1

-sUReN

de consultas SQL: (grupo de & recuento de distinta)

select city,count(distinct(emailId)) from TransactionDetails group by city; 

Equivalente consulta mongo se vería así:

db.TransactionDetails.aggregate([ 
{$group:{_id:{"CITY" : "$cityName"},uniqueCount: {$addToSet: "$emailId"}}}, 
{$project:{"CITY":1,uniqueCustomerCount:{$size:"$uniqueCount"}} } 
]);