MST
星途 面试题库

面试题:MongoDB条件操作符在多条件组合及原子性更新中的应用

假设有一个集合users,文档结构为{userId: 'u1', status: 'active', credits: 100, purchases: [{product: '商品A', date: '2023 - 01 - 01', amount: 50}, {product: '商品B', date: '2023 - 02 - 01', amount: 30}]}。现在需要实现一个复杂更新:如果用户状态为'active'且总购买金额(所有purchases中的amount之和)大于100,将用户积分credits增加20,同时将最近一次购买(按date排序)的商品金额减半。要求使用MongoDB条件操作符以原子性方式完成此更新,写出详细的更新逻辑和对应的代码,并说明如何确保原子性以及条件操作符在其中的关键作用。
30.1万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

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