0

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

shrw
  • 1,719
  • 5
  • 27
  • 50
  • You can always overwrite the whole document (if all else fails) – Sergio Tulentsev Mar 08 '18 at 08:19
  • eee ?? that's risky .. as someone else may be updating something else .. – shrw Mar 08 '18 at 08:23
  • You can overwrite just the `arr`. It's no less risky than blindly shifting item at pos 3 to pos 2 (when other code might have done so milliseconds ago) – Sergio Tulentsev Mar 08 '18 at 08:26
  • eee?? even that's risky .. it has to be simpler .. as someone may still be updating other part of arr – shrw Mar 08 '18 at 08:27
  • 1
    mongodb read is parallel but write is serial. No two write request processed at the same time @andNn – Saikat Hajra Mar 08 '18 at 08:35
  • read is parallel .. which means if 2 people read the data at the same time .. but update at different time.. example .. first one added an obj {_id :4, val:4} to arr. And then the second one reordered it .. this change ( adding of 4 ) will be complete lost – shrw Mar 08 '18 at 09:33
  • Will it be run with the mongo shell or a javascript driver (mongoose)? – Xavier Guihot Mar 12 '18 at 07:16
  • via node.js .. but not mongoose – shrw Mar 12 '18 at 07:19
  • can you give some ref code to solve the issue – shrw Mar 12 '18 at 07:22
  • I think this might help: [How to change order of array with MongoDB?](https://stackoverflow.com/a/35813305/9297144) – Xavier Guihot Mar 12 '18 at 07:24
  • What is the use case ? Are you trying to fix the data to have sorted order in array ? Something like `db.col.update( { }, { $push: { arr: { $each: [add elements(optional)], $sort: {_id:1}}}})` should work. – s7vr Mar 12 '18 at 09:41
  • not sorting .. just reordering .. as per customer requirements – shrw Mar 12 '18 at 09:59

1 Answers1

0

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.

Alex Blex
  • 34,704
  • 7
  • 48
  • 75
  • Hi Alex , Thanks for the effort,, but was looking for something stable. – shrw Mar 16 '18 at 05:21
  • It is quite stable - the simplified version of [2 phase commits](https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/index.html). What are your concerns? – Alex Blex Mar 16 '18 at 10:11
  • what if the application craaashes after getting the lock ,, is it recoverable – shrw Apr 23 '18 at 12:25
  • It's totally up to you. The lock is implemented on application level, so it is totally under your control - how much efforts you can put into recoverability. `a bit of housekeeping` in the answer is for you to decide what to do with orphaned locks. The `const uid = process.pid + '-' + process.hrtime();` is not a random number exactly for this reason. – Alex Blex Apr 23 '18 at 15:26