我有一个架构。
const placeSchema = new Schema({
description: {
fr: String,
en: String,
},
comment: {
fr: String,
en: String,
},
...
...
});
const Place= mongoose.model('Place', placeSchema);
module.exports = Place;
如果我仅想获取我当前正在使用的“ en”值
await Place.find({}, '-description.fr -comment.fr ...')
如果相似字段的数量增加,那么查询的长度也会增加。有没有办法选择所有类似的字段,例如 $ field .fr?
答案 0 :(得分:1)
从技术上讲是有办法的。使用$objectToArray并进行一些结构操作。
它看起来像这样:
db.collection.aggregate([
{
$match: {} //match your document.
},
{
$addFields: {
rootArr: {
$objectToArray: "$$ROOT"
}
}
},
{
$unwind: "$rootArr"
},
{
$match: {
"rootArr.v.en": {
$exists: true
}
}
},
{
$group: {
_id: "$_id",
data: {
$push: {
k: "$rootArr.k",
v: "$rootArr.v.en"
}
}
}
},
{
$replaceRoot: {
newRoot: {
$arrayToObject: "$data"
}
}
}
])
有点“棘手”的想法,您的架构需求有多严格? 您是否考虑过按照以下结构进行构建?
const placeSchema = new Schema({
data: [
{
lang: String,
description: String,
comment: String,
...
}
]
});
答案 1 :(得分:1)
以下汇总将检查所有顶级字段中的子字段en
。如果是事实(如果您严格具有语言属性的字符串值,则应该可以使用),子字段将为{ field: { en: fieldValue.en } }
,否则为{ field: fieldValue }
db.collection.aggregate([
{
$replaceRoot: {
newRoot: {
$arrayToObject: {
$map: {
input: { $objectToArray: "$$ROOT" },
in: {
k: "$$this.k",
v: {
$cond: [
"$$this.v.en", // works for string values, otherwise you will have to check more explicitly
{
en: "$$this.v.en"
},
"$$this.v"
]
}
}
}
}
}
}
}
])
答案 2 :(得分:1)
以上两个答案正是问题的根源。这可能是一种更“ hacky”的处理方式。
首先创建一个生成查询字符串'-description.fr -comment.fr ...'
let select = '';
const selectLanguage = (fields, lang) => {
switch (true) {
case lang === 'fr':
fields.forEach(field => {
select= `${select} -${field}.en `;
});
break;
case lang === 'en':
fields.forEach(field => {
select = `${select} -${field}.fr `;
});
break;
default:
break;
}
return select;
}
这将为英语生成一个字符串,例如' -fieldName1.fr -fieldName2.fr ..'
,对于法语生成一个字符串' -fieldName1.en ..'
。然后,我们可以在上面的查询中使用此语句。
const select = selectLanguage(['description', 'comment', ..], 'en')
await Place.find({}, select) //await Place.find({}, ' -description.fr -comment.fr ..')