MST

星途 面试题库

面试题:MongoDB中事务与聚合管道在简单电商场景的协同应用

假设你正在开发一个简单的电商系统,有两个集合,一个是`products`存储商品信息,另一个是`orders`存储订单信息。订单中包含所购买商品的ID列表。现在要实现一个操作,在一个事务内,更新商品库存(减少已下单数量)并统计该订单所有商品的总价格,需要用到聚合管道计算总价。请描述实现思路并给出大致的代码示例。
12.2万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 开启事务:确保更新库存和统计总价操作在同一个事务内,保证数据一致性。
  2. 更新商品库存:遍历订单中的商品ID列表,找到对应的商品并减少其库存数量。
  3. 统计订单商品总价:使用聚合管道,通过$lookup操作符将订单中的商品ID与products集合关联,然后使用$sum操作符计算总价。
  4. 提交或回滚事务:如果更新库存和统计总价都成功,提交事务;否则,回滚事务。

代码示例(以MongoDB和Node.js为例)

const { MongoClient } = require('mongodb');

// 连接MongoDB
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);

async function updateStockAndCalculateTotal(order) {
    try {
        await client.connect();
        const session = client.startSession();
        session.startTransaction();

        const productsCollection = client.db('ecommerce').collection('products');
        const ordersCollection = client.db('ecommerce').collection('orders');

        // 更新商品库存
        for (const productId of order.productIds) {
            await productsCollection.updateOne(
                { _id: productId },
                { $inc: { stock: -1 } },
                { session }
            );
        }

        // 统计订单商品总价
        const pipeline = [
            {
                $match: { _id: order._id }
            },
            {
                $lookup: {
                    from: 'products',
                    localField: 'productIds',
                    foreignField: '_id',
                    as: 'products'
                }
            },
            {
                $unwind: '$products'
            },
            {
                $group: {
                    _id: null,
                    totalPrice: { $sum: '$products.price' }
                }
            }
        ];

        const result = await ordersCollection.aggregate(pipeline).session(session).toArray();
        const totalPrice = result[0].totalPrice;

        await session.commitTransaction();
        return totalPrice;
    } catch (error) {
        console.error('Transaction failed:', error);
        throw error;
    } finally {
        await client.close();
    }
}

// 使用示例
const order = {
    _id: '123',
    productIds: ['product1Id', 'product2Id']
};

updateStockAndCalculateTotal(order).then(totalPrice => {
    console.log('Total Price:', totalPrice);
}).catch(error => {
    console.error('Error:', error);
});