MongoDB consultar várias collections de uma só vez

users { "_id":"12345", "admin":1 }, { "_id":"123456789", "admin":0 } posts { "content":"Some content", "owner_id":"12345", "via":"facebook" }, { "content":"Some other content", "owner_id":"123456789", "via":"facebook" } 

Aqui está uma amostra do meu mongodb. Eu quero obter todas as mensagens que tem “via” atributo igual a “facebook” e postado por um administrador (“admin”: 1). Não consegui descobrir como adquirir essa consulta. Como o mongodb não é um database relacional, não consegui fazer uma operação de junit. Qual poderia ser a solução ?

Tentar JOIN no MongoDB iria frustrar o propósito de usar o MongoDB. Você poderia, no entanto, usar um DBref e escrever seu código de nível de aplicativo (ou biblioteca) para que ele busque automaticamente essas referências para você.

Ou você pode alterar seu esquema e usar documentos incorporados .

Sua escolha final é deixar as coisas exatamente como estão agora e fazer duas consultas.

Aqui está a resposta para sua pergunta.

 db.getCollection('users').aggregate([ {$match : {admin : 1}}, {$lookup: {from: "posts",localField: "_id",foreignField: "owner_id",as: "posts"}}, {$project : { posts : { $filter : {input : "$posts" , as : "post", cond : { $eq : ['$$post.via' , 'facebook'] } } }, admin : 1 }} ]) 

Ou você pode ir com a opção de grupo mongodb.

 db.getCollection('users').aggregate([ {$match : {admin : 1}}, {$lookup: {from: "posts",localField: "_id",foreignField: "owner_id",as: "posts"}}, {$unwind : "$posts"}, {$match : {"posts.via":"facebook"}}, { $group : { _id : "$_id", posts : {$push : "$posts"} }} ]) 

Você pode usar $lookup (multiple) para obter os registros de várias collections:

Exemplo:

Se você tiver mais collections (eu tenho 3 collections para demonstração aqui, você pode ter mais de 3). e eu quero pegar os dados de 3 collections em um único object:

A coleção é como:

db.doc1.find (). pretty ();

 { "_id" : ObjectId("5901a4c63541b7d5d3293766"), "firstName" : "shubham", "lastName" : "verma" } 

db.doc2.find (). pretty ();

 { "_id" : ObjectId("5901a5f83541b7d5d3293768"), "userId" : ObjectId("5901a4c63541b7d5d3293766"), "address" : "Gurgaon", "mob" : "9876543211" } 

db.doc3.find (). pretty ();

 { "_id" : ObjectId("5901b0f6d318b072ceea44fb"), "userId" : ObjectId("5901a4c63541b7d5d3293766"), "fbURLs" : "http://www.facebook.com", "twitterURLs" : "http://www.twitter.com" } 

Agora sua consulta será como abaixo:

 db.doc1.aggregate([ { $match: { _id: ObjectId("5901a4c63541b7d5d3293766") } }, { $lookup: { from: "doc2", localField: "_id", foreignField: "userId", as: "address" } }, { $unwind: "$address" }, { $project: { __v: 0, "address.__v": 0, "address._id": 0, "address.userId": 0, "address.mob": 0 } }, { $lookup: { from: "doc3", localField: "_id", foreignField: "userId", as: "social" } }, { $unwind: "$social" }, { $project: { __v: 0, "social.__v": 0, "social._id": 0, "social.userId": 0 } } ]).pretty(); 

Então seu resultado será:

 { "_id" : ObjectId("5901a4c63541b7d5d3293766"), "firstName" : "shubham", "lastName" : "verma", "address" : { "address" : "Gurgaon" }, "social" : { "fbURLs" : "http://www.facebook.com", "twitterURLs" : "http://www.twitter.com" } } 

Se você quiser todos os registros de cada coleção, então você deve remover a linha abaixo da consulta:

 { $project: { __v: 0, "address.__v": 0, "address._id": 0, "address.userId": 0, "address.mob": 0 } } { $project: { "social.__v": 0, "social._id": 0, "social.userId": 0 } } 

Depois de remover o código acima, você obterá o registro total como:

 { "_id" : ObjectId("5901a4c63541b7d5d3293766"), "firstName" : "shubham", "lastName" : "verma", "address" : { "_id" : ObjectId("5901a5f83541b7d5d3293768"), "userId" : ObjectId("5901a4c63541b7d5d3293766"), "address" : "Gurgaon", "mob" : "9876543211" }, "social" : { "_id" : ObjectId("5901b0f6d318b072ceea44fb"), "userId" : ObjectId("5901a4c63541b7d5d3293766"), "fbURLs" : "http://www.facebook.com", "twitterURLs" : "http://www.twitter.com" } } 

Como mencionado antes no MongoDB você não pode se juntar entre collections.

Para o seu exemplo, uma solução poderia ser:

 var myCursor = db.users.find({admin:1}); var user_id = myCursor.hasNext() ? myCursor.next() : null; db.posts.find({owner_id : user_id._id}); 

Veja o manual de referência – seção de cursores: http://es.docs.mongodb.org/manual/core/cursors/

Outra solução seria incorporar usuários na coleção de publicações, mas acho que para a maioria dos aplicativos da Web a coleção de usuários precisa ser independente por razões de segurança. A coleção de usuários pode ter funções, permissions, etc.

 posts { "content":"Some content", "user":{"_id":"12345", "admin":1}, "via":"facebook" }, { "content":"Some other content", "user":{"_id":"123456789", "admin":0}, "via":"facebook" } 

e depois:

 db.posts.find({user.admin: 1 }); 

Execute várias consultas ou use documentos incorporados ou consulte “referências de database”.

Uma solução: adicione o indicador isAdmin: 0/1 ao seu documento de coleta de postagem.

Outra solução: use DBrefs

Você pode escrever um exemplo de JavaScript como abaixo e chamar a function quando necessário.

Consulte a ilustração em: http://dbversity.com/mongodb-querying-multiple-collections-with-a-javascript/

 function colListQuery() { var tcol = new Array() tcol= db.getCollectionNames(); for(var i = 1; i < tcol.length ; i++) { query = “db.” + tcol[i] + “.find()”; var docs= eval(query); docs.forEach( function(doc, index){ print( “Database_Name:”, db, “Collection_Name:”, tcol[i], “x_value:”, doc.x, “_id:”, doc._id) }); } } 

Em seguida, chame-o com colListQuery () quando for necessário, conforme mostrado na ilustração.