August
August

Reputation: 12558

Flipping fields in MongoDB document

If I have a document that looks like this for instance:

{
    "a" : "val",
    "b" : "another val"
}

How can I flip specified fields so that the result looks like

{
    "b" : "val",
    "a" : "another val"
}

I've tried db.collection.update({}, {$rename:{'a':'b', 'b':'a'}}) but I get the error Field name duplication not allowed with modifiers

Upvotes: 1

Views: 234

Answers (2)

Bruce Lucas
Bruce Lucas

Reputation: 959

It is worth noting that with the new bulk update operations coming in MongoDB 2.6 it is possible to do this rename in a single server-side operation. As of the time of this posting 2.6 is still in pre-relase; you can check the MongoDB download page for availability. Check the release notes for a complete list of changes and new features.

Here is the mongo shell syntax for doing this field rename in a single server-side command:

var bulk = db.c.initializeOrderedBulkOp();
bulk.find({}).update({$rename: {a:'tmp'}})
bulk.find({}).update({$rename: {b:'a'}})
bulk.find({}).update({$rename: {tmp:'b'}})
bulk.execute()

Upvotes: -1

Neil Lunn
Neil Lunn

Reputation: 151112

This is a classic coin shuffle problem. Probably what you are missing in the above is that you are allways going to collide with having the same field specified when trying to form this update in 1 step. You will have to do it in multiple steps, so logically:

db.collection.update({}, {$rename: { 'a': 'c' }})
db.collection.update({}, {$rename: { 'b': 'a' }})
db.collection.update({}, {$rename: { 'c': 'b' }})

But we can do better and avoid the collision in two steps

db.collection.update({}, {$rename:{ 'a': 'c', 'b': 'd' }})
db.collection.update({}, {$rename:{ 'c': 'b', 'd': 'a' }})

Of course this is not one operation and it's not easy and no you cannot reference the value of another field and update it to another.

And of course, only do this where you really need to change your field names. The $rename manual page covers the use cases. If you just want to see things that way, simply $project the form you want:

 db.collection.aggregate([{$project: { a: "$b", b: "$a" }}])

Upvotes: 3

Related Questions