Mongo come cercare $ con DBRef

Ho un problema (/ (ㄒ o ㄒ) / ~~). Supponiamo che la raccolta A sia

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

e collezione B:

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

Non so come $ cercare la ‘offerta’. Provai

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

e

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

ma non funziona. Qualcuno può aiutare? Grazie.

In realtà, l’altra risposta è sbagliata. È ansible eseguire una ricerca su un campo DBref all’interno del proprio aggregatore e non è necessario il mapreduce per questo.

Soluzione

 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" } ]) 

risultato

 { "_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 spiegazione

Passare in rassegna i DBRef con $ map, rompere ogni DBref in un array, mantenere solo il campo $ id, quindi eliminare il formato k: v con $$ this.v, mantenendo solo ObjectId e rimuovendo tutto il resto. È ora ansible cercare su ObjectId.

Descrizione dettagliata

All’interno dell’aggregatore, un tipo DBREF BSON può essere gestito come un object, con due o tre campi (ref, id e db).

Se fate:

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

Questo è il risultato:

 { "_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 volta trasformato un dbref in un array, puoi eliminare i campi inutili interrogando solo il valore nell’indice 1, in questo modo:

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

risultato:

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

Quindi puoi ottenere finalmente il valore desiderato puntando a “$ myvalue.v”, proprio come questo

 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" } } ]) 

risultato:

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

Ovviamente, in una normale pipeline, non hai bisogno di tutti questi passaggi ridondanti, utilizzando una mappa $ annidata, puoi ottenere lo stesso risultato in una volta sola:

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

risultato:

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

Spero che la spiegazione sia abbastanza chiara, se non mi sento libero di chiedere.

A partire da mongoDB 3.4, questo non è ansible . Non è ansible utilizzare DBRef nella pipeline di aggregazione, ad eccezione della fase di corrispondenza $ .

Vi consiglio vivamente di sbarazzarvi di DBRef e passare ai riferimenti manuali. Tuttavia, se hai davvero bisogno di mantenere DBRef, ecco una (brutta) soluzione:

per prima cosa, crea una nuova raccolta denominata “C”, in cui i DBRef vengono sostituiti dai loro ID utilizzando 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" } ) 

quindi, esegui la query di aggregazione sulla nuova raccolta "C":

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

produzione:

  { "_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 } ] }