För att skapa en generisk fråga skulle man behöva aggregeringsramverket eftersom det har några praktiska operatörer som hjälper dig med detta. Till att börja med skulle du behöva konvertera det inbäddade dokumentet till array av nyckel/värdepar och sedan filtrera arrayen på nyckelfältet som passerar in i språket som parameter.
Konvertera till exempel dokumentet
"title": {
"en": "title en2",
"de": "title de2"
},
till en array
"title": [
{ "k": "en", '"v": "title en2" },
{ "k": "de", "v": "title de2" }
],
med $objectToArray
operatör. Du kan sedan filtrera denna array i nyckelfältet med $filter
operatör som
{
'$filter': {
'input': { '$objectToArray': '$title' },
'cond': { '$eq': ['$$this.k', locale] }
}
}
där variabeln locale härleds från den passerade parametern.
När du har den filtrerade arrayen kräver att du skaffa värdefältet $arrayElemAt
operatorn tillämpas på värdenyckeln som
{
'$arrayElemAt': ['$title.v', 0]
}
Så i slutändan måste du köra en pipeline så här:
var locale = 'en';
db.cs.aggregate([
{ '$match': { "cID" : "00001" } },
{ '$addFields': {
'title': {
'$filter': {
'input': { '$objectToArray': '$title' },
'cond': { '$eq': ['$$this.k', locale] }
}
},
'desc': {
'$filter': {
'input': { '$objectToArray': '$desc' },
'cond': { '$eq': ['$$this.k', locale] }
}
}
} },
{ '$addFields': {
'title': {
'$arrayElemAt': ['$title.v', 0]
},
'desc': {
'$arrayElemAt': ['$desc.v', 0]
}
} }
]);
Och med lite refaktorering:
var locale = 'en';
var getFilterOperatorExpression = function (field) {
return {
'$filter': {
'input': { '$objectToArray': '$'+ field },
'cond': { '$eq': ['$$this.k', locale] }
}
}
};
var getValueOperatorExpression = function (field) {
return {
'$arrayElemAt': ['$'+ field +'.v', 0]
}
};
db.cs.aggregate([
{ '$match': { "cID" : "00001" } },
{ '$addFields': {
'title': getFilterOperatorExpression('title'),
'desc': getFilterOperatorExpression('desc'),
} },
{ '$addFields': {
'title': getValueOperatorExpression('title'),
'desc': getValueOperatorExpression('desc')
} }
]);