mongodb - 使用 MongoDB 的 `$[]` 运算符遍历两个数组并更新相关文档
问题描述
升级到 Mongo 4.0 后,我正在尝试使用 Mongo 的新$[]
功能。我基本上想要做的是接受一个或多个“覆盖”ID并遍历两个数组以使更新过滤匹配那些在“覆盖”ID中传递的更新。我的代码的相关部分如下所示:
if (coverage) {
let arrCoverage = [];
arrCoverage = coverage.split(",");
if (arrCoverage) {
// convert each ID to a mongo ID
let mongoArrCoverage = arrCoverage.map(coverage => new mongo.ObjectID(coverage));
if (mongoArrCoverage) {
try {
let bulk = db.collection("customers").initializeUnorderedBulkOp();
let count = 0;
let batch = 1;
db.collection("customers")
.aggregate([
{
$match: {
"paymentOptions.coverages._id": {
$in: mongoArrCoverage
}
}
},
{
$unwind: "$paymentOptions"
},
{
$unwind: "$coverages"
},
{
$match: {
"coverages._id": {
$in: mongoArrCoverage
}
}
},
{
$project: {
_id: 0,
coverages_id: "$coverages._id",
"coverages.status": "$coverages.status"
}
}
])
.forEach(function(doc) {
let coverages_id = doc.paymentOptions.coverages_id;
bulk
.find({
"paymentOptions.coverages._id": coverages_id
})
.updateOne({
$set: {
"paymentOptions.$[].coverages.$[].coverageEnd": lastDayOfMonth,
"paymentOptions.$[].coverages.$[].status": doc.paymentOptions.coverages.status == "active" ? null : doc.paymentOptions.coverages.status,
"paymentOptions.$[].coverages.$[].lastAdvanceDate": today
}
});
count++;
if (count == batch) {
bulk.execute();
bulk = db.collection("customers").initializeUnorderedBulkOp();
count = 0;
}
});
if (count > 0) {
bulk.execute();
}
res.sendStatus(200);
} catch (e) {
console.log(e);
}
}
}
}
};
但这似乎并没有进行预期的更新。我认为问题可能出在我最初的聚合中吗?这段代码看起来正确吗?在我们之前的模型中,“coverages”数组位于文档的根目录上。现在它是“paymentOptions”中的一个属性,也是一个数组,我假设我必须$unwind
在初始聚合中使用这两个数组。
顺便说一句,文档的相关部分如下所示:
{
_id: <ObjectId>,
someProp: <value>,
paymentOptions: [
{
_id: <ObjectId>,
otherProp: <value>,
coverages: [
{
_id: <ObjectId>, // Want to match on this
coverageStart: <Date>,
coverageEnd: <Date>, // Want to update this
status: "active"
},
{
_id: <ObjectId>, // Want to match on this
coverageStart: <Date>,
coverageEnd: <Date>, // Want to update this
status: "active"
}
]
}
]
}
解决方案
您必须使用数组过滤器。此外,要展开嵌套数组,您必须使用点表示法来包含整个路径。
像应该工作的东西
if (coverage) {
let arrCoverage = [];
arrCoverage = coverage.split(",");
if (arrCoverage) {
// convert each ID to a mongo ID
let mongoArrCoverage = arrCoverage.map(coverage => new mongo.ObjectID(coverage));
if (mongoArrCoverage) {
try {
let bulk = db.collection("customers").initializeUnorderedBulkOp();
let count = 0;
let batch = 1;
db.collection("customers").aggregate([{
$match: {
"paymentOptions.coverages._id": {
$in: mongoArrCoverage
}
}
}, {
$unwind: "$paymentOptions"
}, {
$unwind: "$paymentOptions.coverages"
}, {
$match: {
"paymentOptions.coverages._id": {
$in: mongoArrCoverage
}
}
}, {
$project: {
_id: 0,
"paymentOptions_id": "$paymentOptions._id",
"coverages_id": "$paymentOptions.coverages._id",
"coverages_status": "$paymentOptions.coverages.status"
}
}]).forEach(function(doc) {
let paymentOption_id = doc.paymentOptions_id;
let coverages_id = doc.coverages_id;
let status = doc.coverages_status;
bulk.find({}).arrayFilters([
{"po._id": paymentOption_id},
{"cr._id": coverages_id}]).updateOne({
$set: {
"paymentOptions.$[po].coverages.$[cr].coverageEnd": lastDayOfMonth,
"paymentOptions.$[po].coverages.$[cr].status": status == "active" ? null : status,
"paymentOptions.$[po].coverages.$[cr].lastAdvanceDate": today
}
}); count++;
if (count == batch) {
bulk.execute();
bulk = db.collection("customers").initializeUnorderedBulkOp();
count = 0;
}
});
if (count > 0) {
bulk.execute();
}
res.sendStatus(200);
}
catch (e) {
console.log(e);
}
}
}
}
};
推荐阅读
- vba - 如何在导入 Access Table 之前转换文件?
- list - Markdown Nested Lists with Multiple Lines under Single Bullet
- shell - How do you recursively `scp` files specified by command output?
- flutter - Flutter Image 和 AnimatedSize 小部件
- java - Android-studio:如何调用期望来自同一类的视图参数的方法?
- python - 如何重复提取两个固定标记之间的字符串
- python - 如何临时覆盖字典的成员?
- sharepoint - Sharepoint 列表计算列未正确显示
- devops - 圣杯和在 AWS 代码构建中将 jq 1.3 升级到 1.6
- javascript - 我的“过渡”事件侦听器不起作用吗?