首页 > 解决方案 > 在 MongoDB 文档中移动元素

问题描述

背景:

客户是具有名称字段的对象。

线是具有以下字段的对象:

集合“行”包含作为行对象的文档。


问题:

我正在尝试实现一个可以执行以下操作的程序:

  1. currentCustomerprocessed
  2. 设置currentCustomer为第一个元素inLine
  3. 弹出第一个元素inLine

由于一个字段的新值取决于另一个字段的先前值,因此原子性在这里很重要。

到目前为止我尝试了什么:

天真的方法

db.collection('line').findOneAndUpdate({
    _id: new ObjectId(lineId),
}, {
    $set: {
        currentCustomer: '$inLine.0',
    },
    $pop: {
        inLine: -1,
    },
    $push: {
        processed: '$currentCustomer',
    },
});

但是,currentCustomer它被设置为一个字面意思是“$inLine.0”processed的字符串,并且有一个字面意思是“$currentCustomer”的字符串。

聚合方法

db.collection('line').findOneAndUpdate({
    _id: new ObjectId(lineId),
}, [{
    $set: {
        currentCustomer: '$inLine.0',
    },
    $pop: {
        inLine: -1,
    },
    $push: {
        processed: '$currentCustomer',
    },
}]);

但是,我收到以下错误:

MongoError:管道阶段规范对象必须只包含一个字段。

多阶段聚合方法

db.collection('line').findOneAndUpdate({
    _id: new ObjectId(lineId),
}, [{
    $set: {
        currentCustomer: '$inLine.0',
    },
}, {
    $pop: {
        inLine: -1,
    },
}, {
    $push: {
        processed: '$currentCustomer',
    },
}]);

但是,$pop$push是无法识别的管道阶段名称。

我尝试只使用$set阶段来制作它,但它最终变得非常丑陋,我仍然无法让它工作。

标签: javascriptmongodbmongodb-nodejs-driver

解决方案


根据turivishal 的回答,它是这样解决的:

db.collection('line').findOneAndUpdate({
    _id: new ObjectId(lineId),
}, [{
    $set: {
        // currentCustomer = inLine.length === 0 ? null : inLine[0]
        currentCustomer: {
            $cond: [
                { $eq: [{ $size: '$inLine' }, 0] },
                null,
                { $first: '$inLine' },
            ],
        },
        // inLine = inLine.slice(1)
        inLine: {
            $cond: [
                { $eq: [{ $size: '$inLine' }, 0] },
                [],
                { $slice: ['$inLine', 1, { $size: '$inLine' }] },
            ],
        },
        // if currentCustomer !== null then processed.push(currentCustomer)
        processed: {
            $cond: [
                {
                    $eq: ['$currentCustomer', null],
                },
                '$processed',
                {
                    $concatArrays: [
                        '$processed', ['$currentCustomer'],
                    ],
                }
            ],
        },
    },
}]);

推荐阅读