unwind inner hacer example ejemplo como mongodb spring-data-mongodb

inner - mongodb join collections



Mongo cómo $ buscar con DBRef (2)

A partir de mongoDB 3.4, esto no es posible . No puede usar DBRef en la canalización de agregación, excepto en la etapa $match .

Le recomiendo que se deshaga de DBRef y cambie a referencias manuales. Sin embargo, si realmente necesitas mantener DBRef, aquí hay una solución (fea):

primero, crea una nueva colección llamada "C", donde los DBRefs son reemplazados por sus Ids usando mapReduce:

db.A.mapReduce( function() { var key = this._id; var value = []; for ( var index = 0; index < this.bid.length; index++){ value.push(this.bid[index].$id); } emit(key, value); }, function(key,values) { return values; }, { "query": {}, "out": "C" } )

luego, ejecute su consulta de agregación en la nueva colección "C":

db.C.aggregate([ { $unwind:"$value" }, { $lookup:{ from:"B", localField:"value", foreignField:"_id", as:"bs" } } ]);

salida:

{ "_id":ObjectId("582abcd85d2dfa67f44127e1"), "value":ObjectId("582abcd85d2dfa67f44127e0"), "bs":[ { "_id":ObjectId("582abcd85d2dfa67f44127e0"), "status":1, "seq":0 } ] }{ "_id":ObjectId("582abcd85d2dfa67f44127e1"), "value":ObjectId("582abcd85d2dfa67f44127e1"), "bs":[ { "_id":ObjectId("582abcd85d2dfa67f44127e1"), "status":1, "seq":0 } ] }

Tengo un problema (/ (ㄒ o ㄒ) / ~~). Supongamos que la colección A es

{ "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "bid" : [ DBRef("B", ObjectId("582abcd85d2dfa67f44127e0")), DBRef("B", ObjectId("582abcd85d2dfa67f44127e1")) ] }


y Colección B:

{ "_id" : ObjectId("582abcd85d2dfa67f44127e0"), "status" : NumberInt(1), "seq" : NumberInt(0) }, { "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "status" : NumberInt(1), "seq" : NumberInt(0) }


No sé cómo $ buscar la ''oferta''. Lo intenté

db.A.aggregate( [ {$unwind: {path: "$bid"}}, {$lookup: {from: "B", localField: "bid", foreignField: "_id", as: "bs"}}, ] )


y

db.A.aggregate( [ {$unwind: {path: "$bid"}}, {$lookup: {from: "B", localField: "bid.$id", foreignField: "_id", as: "bs"}}, ] )


pero no funciona ¿Alguien puede ayudar? Gracias.


En realidad, la otra respuesta es incorrecta. Es posible hacer una búsqueda en un campo DBref dentro de su agregador, y no necesita mapreduce para eso.

Solución

db.A.aggregate([ { $project: { B_fk: { $map: { input: { $map: { input:"$bid", in: { $arrayElemAt: [{$objectToArray: "$$this"}, 1] }, } }, in: "$$this.v"}}, } }, { $lookup: { from:"B", localField:"B_fk", foreignField:"_id", as:"B" } ])

resultado

{ "_id" : ObjectId("59bb79df1e9c00162566f581"), "B_fk" : null, "B" : [ ] }, { "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "B_fk" : [ ObjectId("582abcd85d2dfa67f44127e0"), ObjectId("582abcd85d2dfa67f44127e1") ], "B" : [ { "_id" : ObjectId("582abcd85d2dfa67f44127e0"), "status" : NumberInt("1"), "seq" : NumberInt("0") } ] }

Breve explicación

Recorra los DBRefs con $ map, divida cada DBref en una matriz, mantenga solo el campo $ id, luego elimine el formato k: v con $$ this.v, manteniendo solo el ObjectId y eliminando todo el resto. Ahora puede buscar en el ObjectId.

Explicación paso a paso

Dentro del agregador, un tipo BSON DBRef puede manejarse como un objeto, con dos o tres campos (ref, id y db).

Si lo haces:

db.A.aggregate([ { $project: { First_DBref_as_array: {$objectToArray:{$arrayElemAt:["$bid",0]}}, Second_DBref_as_array: {$objectToArray:{$arrayElemAt:["$bid",1]}}, } }, ])

Este es el resultado:

{ "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "First_DBref_as_array : [ { "k" : "$ref", "v" : "B" }, { "k" : "$id", "v" : ObjectId("582abcd85d2dfa67f44127e0") } ], "Second_DBref_as_array" : [ { "k" : "$ref", "v" : "B" }, { "k" : "$id", "v" : ObjectId("582abcd85d2dfa67f44127e0") } ] }

Una vez que haya transformado un dbref en una matriz, puede deshacerse de los campos inútiles consultando solo el valor en el índice 1, como esto:

db.A.aggregate([ { $project: { First_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]}, Second_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]}, } }, ])

resultado:

{ "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "First_DBref_as_array" : { "k" : "$id", "v" : ObjectId("582abcd85d2dfa67f44127e0") }, "Second_DBref_as_array" : { "k" : "$id", "v" : ObjectId("582abcd85d2dfa67f44127e0") } }

Luego, finalmente puede obtener el valor que desea al señalar "$ myvalue.v", así como así

db.A.aggregate([ { $project: { first_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]}, second_DBref_as_array: {$arrayElemAt: [{$objectToArray:{$arrayElemAt:["$bid",0]}},1]}, } }, { $project: { first_DBref_as_ObjectId: "$first_DBref_as_array.v", second_DBref_as_ObjectId: "$second_DBref_as_array.v" } } ])

resultado:

{ "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "first_DBref_as_ObjectId" : ObjectId("582abcd85d2dfa67f44127e0"), "second_DBref_as_ObjectId" : ObjectId("582abcd85d2dfa67f44127e0") }

Obviamente, en una tubería normal, no necesita todos estos pasos redundantes, utilizando un mapa $ anidado, puede obtener el mismo resultado de una sola vez:

db.A.aggregate([ { $project: { B_fk: { $map : {input: { $map: { input:"$bid", in: { $arrayElemAt: [{$objectToArray: "$$this"}, 1 ]}, } }, in: "$$this.v"}}, } }, ])

resultado:

{ "_id" : ObjectId("582abcd85d2dfa67f44127e1"), "B_fk" : [ ObjectId("582abcd85d2dfa67f44127e0"), ObjectId("582abcd85d2dfa67f44127e1") ] }

Espero que la explicación sea lo suficientemente clara, si no, no dude en preguntar.