- 更新逻辑:
- 首先通过
$match
筛选出状态为active
且总购买金额大于100的用户。
- 使用
$addFields
计算总购买金额并找到最近一次购买记录。
- 利用
$set
来更新credits
和最近一次购买记录中的amount
。
- 代码实现:
db.users.aggregate([
// 筛选状态为active且总购买金额大于100的用户
{
$match: {
status: 'active',
$expr: {
$gt: [
{ $sum: "$purchases.amount" },
100
]
}
}
},
// 计算总购买金额并找到最近一次购买记录
{
$addFields: {
totalPurchase: { $sum: "$purchases.amount" },
latestPurchase: {
$arrayElemAt: [
{
$sortArray: {
input: "$purchases",
sortBy: { date: -1 }
}
},
0
]
}
}
},
// 更新credits和最近一次购买记录中的amount
{
$set: {
credits: { $add: ["$credits", 20] },
"purchases.$[elem].amount": { $divide: ["$latestPurchase.amount", 2] }
},
$arrayFilters: [
{ "elem.product": "$latestPurchase.product" }
]
},
// 将更新结果写回集合
{
$merge: {
into: "users",
on: "_id",
whenMatched: "replace",
whenNotMatched: "discard"
}
}
]);
- 确保原子性:
- 在MongoDB中,上述更新操作利用
$merge
将计算结果写回原集合,$merge
操作在3.6版本及以上是原子性的。整个聚合管道的计算结果会作为一个整体写入目标集合,保证了更新的原子性,即要么整个更新操作成功,要么整个失败,不会出现部分更新的情况。
- 条件操作符的关键作用:
$match
条件操作符用于筛选符合特定条件(状态为active
且总购买金额大于100)的文档,确保只对符合条件的用户进行后续操作。
$expr
与$match
配合,在聚合管道中使用表达式进行复杂条件匹配,这里用于计算总购买金额并与100比较。
$sum
在$expr
中计算purchases
数组中amount
字段的总和,是实现复杂条件匹配的关键部分。
$addFields
中的$sortArray
和$arrayElemAt
用于找到最近一次购买记录,$sortArray
按日期降序排列purchases
数组,$arrayElemAt
取出排序后的第一个元素(即最近一次购买记录)。
$set
用于更新文档字段,通过$add
增加credits
积分,同时利用$divide
减半最近一次购买商品的金额。$arrayFilters
确保只更新最近一次购买记录对应的amount
字段,避免错误更新其他购买记录。