3

Well, someone done goofed. Wasn't me, but I get to fix it. What I need to do, is replace the _id of each and every document in the collection with a new UUID.

My plan was aggregating the entire collection, use $addFields to replace the _id, then merge it back into itself, replacing the records. Fortunately, there is a secondary (composite) key I can use for merging, so I'm good there — I think, because I haven't gotten there yet.

The problem I face is generating a unique (that's kinda the point of it) UUID during the $addFields stage.

db.foo.agregate([
    {
        $addFields: {
            // I really just need the UUID string itself, hence the split
            '_id': UUID().toString().split('"')[1]
        }
    }
    // here's where the merge would go
])

The problem here is that UUID() is called only once, so I get all the same IDs. That's not quite what I want.

Now the tedious way would be to do this one by one, from a loop. But is there a way to do this from within an aggregation pipeline in one go?


Now I found this question asking basically the same question, but it was solved by not using an UUID, using sequential keys instead, so it really isn't an answer to my question.

SQB
  • 3,926
  • 2
  • 28
  • 49
  • This is much better approach avoiding security issues when enabling javascript on your database. Please see the asnwer here: https://stackoverflow.com/a/71733315/12002600 – Bitfinicon Apr 04 '22 at 07:27

2 Answers2

4

So this answer is just to generate unique UUIDs by calling UUID() from a $function. Try this:

db.collectionName.aggregate([
    {
        $addFields: {
            _id: {
                $function: {
                    body: function() {
                        return UUID().toString().split('"')[1];
                    },
                    args: [],
                    lang: "js"
                }
            }
        }
    }
])

btw, its only works in MongoDB version >= 4.4. Output:

/* 1 */
{
    "_id" : "5dc9316a-50a8-4013-8090-06fc66cdce9f",
    "dummy" : "data"
},

/* 2 */
{
    "_id" : "062ebc8f-4455-4a81-a9e0-34f6c7132cab",
    "dummy" : "data"
},

/* 3 */
{
    "_id" : "94eef4b8-9c0e-4910-a1cb-58443a63a036",
    "dummy" : "data"
}
Dheemanth Bhat
  • 4,269
  • 2
  • 21
  • 40
  • 1
    Yes, that did it! Making a function that returned the UUID was the trick that did it; the generate UUIDs weren't _weird_, but all the same. This solved it. – SQB Mar 31 '21 at 19:59
  • I got this message: `$function not allowed in this atlas tier`. Is this was available for all tiers last year or is it recent? – Misael Abanto Jun 30 '22 at 18:55
  • Sorry I wrote that query in local never tried in cloud. Check this answer if it helps: https://stackoverflow.com/questions/66688549/mongodb-update-all-the-documents-with-unique-id/71733315#71733315 – Dheemanth Bhat Jun 30 '22 at 19:26
1

If what you need to do is

What I need to do, is replace the _id of each and every document in the collection with a new UUID.

... and you can use ObjectIds instead of UUIDs, then:

  • Project out the _id
  • $out into a new collection

The server should generate new _ids for each document during the insert.

Then:

  • Drop the original collection
  • Rename the new collection into the original name
D. SM
  • 13,584
  • 3
  • 12
  • 21