With mongo 3.6
$position
is for mongo $push
how do i change the position of the existing element of array.
{ "name":"a", "arr":[ {_id:1, val:1}, {_id:3, val:3}, {_id:2, val:2}, ] }
need to change the position of the 3rd element to second
1 Answers
Answers 1
Not possible the way the question imply. There are no atomic operations to reorder embedded documents and no transactions in current v3.6.
The comments suggest the real question is how to reorder subdocuments safely considering possible concurrent writes.
You can implement optimistic locking on application level:
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") } })
It requires a bit of housekeeping to clear residual locks if an application died somewhere between updateOne
and replaceOne
though.
It's up to you how to catch exceptions - you can retry few times, or give up immediately.
0 comments:
Post a Comment