Para criar uma consulta genérica, seria necessário o framework de agregação, pois possui alguns operadores úteis para ajudá-lo com isso. Para começar, você precisaria converter o documento incorporado em uma matriz de pares de chave/valor e, em seguida, filtrar a matriz no campo de chave passando a localidade como parâmetro.
Por exemplo, converta o documento
"title": {
"en": "title en2",
"de": "title de2"
},
para uma matriz
"title": [
{ "k": "en", '"v": "title en2" },
{ "k": "de", "v": "title de2" }
],
usando
$objectToArray
operador. Você pode filtrar essa matriz no campo-chave usando o $filter
operador como {
'$filter': {
'input': { '$objectToArray': '$title' },
'cond': { '$eq': ['$$this.k', locale] }
}
}
onde a localidade da variável é derivada do parâmetro passado.
Depois de ter a matriz filtrada, obter o campo de valor requer o
$arrayElemAt
operador aplicado na chave de valor como {
'$arrayElemAt': ['$title.v', 0]
}
Então, no final, você terá que executar um pipeline como este:
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]
}
} }
]);
E com alguma refatoração:
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')
} }
]);