mongo在添加后更改数组元素的$位置

时间:2018-03-08 08:18:32

标签: mongodb

使用mongo 3.6

$position适用于mongo $push

如何更改数组现有元素的位置。

{
"name":"a",
"arr":[
   {_id:1, val:1},
   {_id:3, val:3},
   {_id:2, val:2},
]
}

需要将第3个元素的位置更改为第二个

1 个答案:

答案 0 :(得分:0)

问题所暗示的方式不可能。在当前的v3.6中没有原子操作来重新排序嵌入文档和没有事务。

评论表明真正的问题是如何在考虑可能的并发写入的情况下安全地重新排序子文档。

您可以在应用程序级别实现乐观锁定:

const uid = process.pid + '-' + process.hrtime();

// lock the document for updates
db.collection.updateOne({_id, reordering: {$exists: false}}, {$set: {reordering: uid}})
.then(res=>{
    if (res.result.nModified !== 1) {
        throw new Error("concurent reordering or wrong _id")
    }
})
.then(()=>db.collection.findOne({_id, reordering:uid}))
.then(doc=>{
    if (!doc) {
        throw new Error("concurent write")
    }
    // reorder
    doc.arr.splice(1, 0, doc.arr.splice(2, 1)[0]);      
    Reflect.deleteProperty(doc, 'reordering');
    // commit and unlock
    return db.collection.replaceOne({_id, reordering: uid}, doc)
})
.then(res=>{
    if (res.result.nModified !== 1) {
        throw new Error("concurrent write")
    }
})

如果应用程序在updateOnereplaceOne之间死亡,则需要一些清理工作才能清除残留锁。

由您决定如何捕获异常 - 您可以重试几次,或立即放弃。