Mr.k1n1
Mr.k1n1

Reputation: 74

generate unique id in nested document - Pymongo

generate unique id in nested document - Pymongo

my database looks like this...

{
  "_id":"5ea661d6213894a6082af6d1",

  "blog_id":"blog_one",

  "comments":  [
          {
            "user_id":"1",
            "comment":"comment for blog one this is good"
          },
          {
            "user_id":"2",
            "comment":"other for blog one"
          },
  ]
}

I want to add unique id in each and every comment,

I want it to output like this,

{
  "_id":"5ea661d6213894a6082af6d1",

  "blog_id":"blog_one",

  "comments": [
           {
            "id" : "something"     (auto generate unique),
            "user_id":"1",
            "comment":"comment for blog one this is good"
           },
           {
            "id" : "something"    (auto generate unique),
            "user_id":"2",
            "comment":"other for blog one"
           },
     ]
}

I'm using PyMongo, is there a way to update this kind of document?

it's possible or not?

Upvotes: 0

Views: 1793

Answers (2)

prasad_
prasad_

Reputation: 14317

This update will add an unique id value to each of the comments array with nested documents. The id value is calculated based upon the present time as milliseconds. This value is incremented for each array element to get the new id value for the nested documents of the array.

The code runs with MongoDB version 4.2 and PyMongo 3.10.

pipeline = [
  { 
      "$set": {
         "comments": { 
             "$map": {
                 "input": { "$range": [ 0, { "$size": "$comments" } ] },
                 "in": {
                     "$mergeObjects": [ 
                         { "id": { "$add": [ { "$toLong" : datetime.datetime.now() }, "$$this" ] } },
                         { "$arrayElemAt": [ "$comments", "$$this" ] }
                     ]
                 }
             }
         }
      }
  }
]

collection.update_one( { }, pipeline )

The updated document:

{
        "_id" : "5ea661d6213894a6082af6d1",
        "blog_id" : "blog_one",
        "comments" : [
                {
                        "id" : NumberLong("1588179349566"),
                        "user_id" : "1",
                        "comment" : "comment for blog one this is good"
                },
                {
                        "id" : NumberLong("1588179349567"),
                        "user_id" : "2",
                        "comment" : "other for blog one"
                }
        ]
}



[ EDIT ADD ]

The following works from mongo shell. It adds unique id for the comments array's nested documents - unique across the documents.

db.collection.aggregate( [
  { 
      "$unwind": "$comments" },
  { 
      "$group": { 
          "_id": null, 
          "count": { "$sum": 1 }, 
          "docs": { "$push": "$$ROOT"  },
          "now": { $first: "$$NOW" }
      } 
  },
  { 
      "$addFields": {
          "docs": { 
              "$map": {
                   "input": { "$range": [ 0, "$count" ] },
                   "in": {
                       "$mergeObjects": [ 
                           { "comments_id": { "$add": [ { "$toLong" : "$now" }, "$$this" ] } },
                           { "$arrayElemAt": [ "$docs", "$$this" ] }
                     ]
                 }
             }
         }
      }
  },
  { 
      "$unwind": "$docs" 
  },
  { 
      "$addFields": { 
          "docs.comments.comments_id": "$docs.comments_id" 
      } 
  },
  { 
      "$replaceRoot": { "newRoot": "$docs" } 
  },
  { 
      "$group": { 
          "_id": { "_id": "$_id", "blog_id": "$blog_id" }, 
          "comments": { "$push": "$comments" } 
      } 
  },
  { 
      $project: { 
          "_id": 0, 
          "_id": "$_id._id", 
          "blog_id": "$_id.blog_id", 
          "comments": 1 
      } 
  }
] ).forEach(doc => db.blogs.updateOne( { _id: doc._id }, { $set: { comments: doc.comments } } ) )

Upvotes: 2

D. SM
D. SM

Reputation: 14530

You can use ObjectId constructor to create the ids and place them in your nested documents.

Upvotes: 0

Related Questions