如何解决在MongoDB中查询本地化数据
具有这样的“本地化”数据:
{
"cs": [
{
"cID": "00001","title": {
"en": "title en1","de": "title de1"
},"desc": {
"en": "desc en1","de": "desc de1"
},"startDate": 20210801,"endDate": 20210809,"numDays": 8
},{
"cID": "00002","title": {
"en": "title en2","de": "title de2"
},"desc": {
"en": "desc en2","de": "desc de2"
},"startDate": 20210701,"endDate": 20210715,"numDays": 14
}
]
}
考虑用户语言环境(传递给查询作为参数)的最佳方式是什么?例如,如果传递了“ en”,则查询应返回“ cID”:“ 00001”:
{
"cID": "00001","title": "title en1","desc": "desc en1","numDays": 8
}
理想情况下,查询应该是“通用”查询,而不是专门过滤“ title”和“ desc”对象。
我知道:
db.cs.find({
"cID": "00001"
},{
"_id": 0,"cID": 1,"title": "$title.en","desc": "$desc.en","startDate": 1,"endDate": 1,"numDays": 1
})
会给我的
[
{
"cID": "00001","endDate": 2.0210809e+07,"numDays": 8,"startDate": 2.0210801e+07,"title": "title en1"
}
]
,但是在不同的查询中使用多种语言环境和不同的数据模型来处理它会很棘手。
蒙哥游乐场:https://mongoplayground.net/p/9erh-VYiOO4
解决方法
要创建一个通用查询,需要一个聚合框架,因为它有一些方便的运算符可以帮助您。首先,您需要将嵌入的文档转换为键/值对的数组,然后在将字段作为参数传递的键字段上对数组进行过滤。
例如,转换文档
"title": {
"en": "title en2","de": "title de2"
},
到数组
"title": [
{ "k": "en",'"v": "title en2" },{ "k": "de","v": "title de2" }
],
使用$objectToArray
运算符。然后,您可以使用$filter
运算符作为
{
'$filter': {
'input': { '$objectToArray': '$title' },'cond': { '$eq': ['$$this.k',locale] }
}
}
其中变量语言环境是从传递的参数派生的。
具有过滤后的数组后,获取value字段需要将$arrayElemAt
运算符应用于value键上,
{
'$arrayElemAt': ['$title.v',0]
}
因此,最后您必须运行这样的管道:
var locale = 'en';
db.cs.aggregate([
{ '$match': { "cID" : "00001" } },{ '$addFields': {
'title': {
'$filter': {
'input': { '$objectToArray': '$title' },locale] }
}
},'desc': {
'$filter': {
'input': { '$objectToArray': '$desc' },locale] }
}
}
} },{ '$addFields': {
'title': {
'$arrayElemAt': ['$title.v',0]
},'desc': {
'$arrayElemAt': ['$desc.v',0]
}
} }
]);
并进行一些重构:
var locale = 'en';
var getFilterOperatorExpression = function (field) {
return {
'$filter': {
'input': { '$objectToArray': '$'+ field },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')
} }
]);
,
您可以尝试
-
$reduce
迭代title
数组的循环,$cond
匹配local
并将匹配结果返回给值,描述数组的过程相同
{
$addFields: {
title: {
$reduce: {
input: "$title",initialValue: "",in: {
$cond: [{ $eq: ["$$this.locale","pl"] },"$$this.value","$$value"]
}
}
},description: {
$reduce: {
input: "$description","$$value"]
}
}
}
}
}
对于通用选项,您可以使函数具有两个参数,第一个是带有$
符号的输入字段,第二个是语言环境:
function languageFilter(inputField,locale) {
return {
$reduce: {
input: inputField,in: {
$cond: [{ $eq: ["$$this.locale",locale] },"$$value"]
}
}
};
}
您的最终查询将是:
let locale = "pl";
db.cs.aggregate([
{ $match: { cID: "00001" } },{
$addFields: {
title: languageFilter("$title",locale)
description: languageFilter("$description",locale)
}
}
]);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。