背景:
客户是一个具有名称字段的对象。
线是一个具有以下字段的对象:
inLine
- 客户数组currentCustomer
- 客户已处理
- 一组客户
集合“line”包含作为行对象的文档。
问题:
我正在尝试实现一个执行以下操作的程序:
- 将
currentCustomer
推送到已处理
- 将
currentCustomer
设置为inLine
中的第一个元素 - 弹出
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: A pipeline stage specification object must contain exactly one field.
多阶段聚合方法
db.collection('line').findOneAndUpdate({
_id: new ObjectId(lineId),
}, [{
$set: {
currentCustomer: '$inLine.0',
},
}, {
$pop: {
inLine: -1,
},
}, {
$push: {
processed: '$currentCustomer',
},
}]);
但是,$pop
和 $push
是无法识别的管道阶段名称。
我尝试仅使用 $set
阶段来制作它,但结果非常丑陋,而且我仍然无法让它工作。
最佳答案
基于turivishal's answer ,它是这样解决的:
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'],
],
}
],
},
},
}]);
关于javascript - 在 MongoDB 文档中移动元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64861667/