Sunday, March 18, 2018

mongo change $position of an array element after addition

Leave a Comment

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment