11

mongodb 2.1.4(The Node Driver)

I'm currently trying to create a new ObjectID for each message I insert into an array(the array being a subdocument).

I figure this way - All CRUD operations can easily be performed on each message in the array.

For Example:

The "threads" collection(Note- An ObjectId for each message)

{
    "_id": ObjectId("1234132413424123"), //A thread id
    messages:[
        {
            _id :ObjectId("134124412341234"),// A message id
            "message":"MongoDB is my friend"

        },
        {
            _id :ObjectId("534124412342377"),
            "message":"MongoDB is my friend too"

        },
        ...
    ]
},
{
    "_id": ObjectId("22341324134224234"),
    messages:[
        {
            _id :ObjectId("8341244123411235"),
            "message":"Something clever"

        },
        {
            _id :ObjectId("134124412342376"),
            "message":"blah blah blah"

        },
        ...
    ]
}

What I'm currently doing right now:

var query = {};

query["_id"] = new ObjectID(threadID);

var update = {$push: {}};    //I write the update object externally just for aesthetics

update.$push["messages"] = newMessage; 

var threadsCollection = db.collection('threads');
threadsCollection.findOneAndUpdate(query,update, function (err, result) {
    if (err) {
        console.log(err);
    } 
    db.close();
});

Problem:

Unlike "insert" for collections, an update with $push does not create a new ObjectId for each message added to the array.

Question:

Is there a standard way of creating an ObjectID during a $push into the child array? Or should we just manually create an ObjectID and add it to the child beforehand?

Nick Pineda
  • 6,354
  • 11
  • 46
  • 66
  • Check out a better approach https://www.baeldung.com/spring-boot-mongodb-auto-generated-field. you can user sequence generator for child objects as well – MohdTausif Jan 24 '19 at 05:57

3 Answers3

20

Not a mongodb expert but, if I understand you correctly, you wish the _id field of the subdocument to be inserted automatically.

I created threads db and then inserted the first message in the messages collection using the following command:

db.messages.insert({messages:[{_id:ObjectId(), message:"Message 1."}]}); 

Notice the _id:ObjectId() field. The result is as follow:

enter image description here

Now that I have an ObjectId(56...), I can update that particular record and insert more messages to it. And the command is as follow:

db.messages.update({"_id":ObjectId("56...")}, 
{$push:{messages:{_id:ObjectId(), message:"I am message 2."}}});

And the above would insert the new message in the collection. See below screenshots:

enter image description here

and finally after a few updates the collection looks as follow:

enter image description here

All the _id fields in the messages array are automatically generated.

It might not be a good idea to use _id fields for various reasons. Please Google for more details on whether to use _id as key for subdocuments or not.

I used MongoDB shell version 3.0.6 for the commands.

EDIT 28-01-2016 16:09

Since the above solution was based on MongoDB shell, I decided to do another test using Node.js driver for MongoDB. First of all, I declare ObjectID variable as follow

var ObjectID = require('mongodb').ObjectID;

I will use the ObjectID with document id of the thread to which the message should be inserted as follow in my update and findOneAndUpdate function calls

app.get('/insertNewMessage', function(req, res) {
    db.collection("messages").findOneAndUpdate({
        _id: new ObjectID('56aa3554e90911b64c36a424')
    }, {
        $push: {
            messages: {
                _id: new ObjectID(),
                message: "From NodeJS with <3 using findOneAndUpdate.Bye."
            }
        }
    }, function(err, result) {
        if (err)
            res.json(err);
        else
            res.json(result);
    });
});

Tested both and works just fine. See the screenshot below:

enter image description here

Raf
  • 7,505
  • 1
  • 42
  • 59
  • Here is a slight modification to this solution if you are using the Node Driver. You can append to the child object that will be added to the array like this ```newMessage["_id"] = new ObjectID();``` and then update the collection like this ```threadCollection.findOneAndUpdate(query,{$push:{messages:newMessage}}});``` – Nick Pineda Jan 28 '16 at 02:55
  • I've Googled if it was good practice to do this, but didn't come away with a sure answer. – Nick Pineda Jan 28 '16 at 02:58
  • 1
    In regards to whether it is a good practice or not, this might be a good read http://stackoverflow.com/questions/12211138/creating-custom-object-id-in-mongodb and this http://stackoverflow.com/questions/13472589/mongo-id-for-subdocument-array – Raf Jan 28 '16 at 16:25
0

ObjectId.GenerateNewId() can be used in Constructor of class

using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes;

public class test
{
[BsonRepresentation(BsonType.ObjectId)]
public ObjectId test_uid {get; set;}
public string name{get; set;}

public test(){
    test_uid = ObjectId.GenerateNewId();
}

} 
-1

Sorry for the breech of protocol but I do no have enough rep to comment on the main thread.

I have been looking at how to generate a JSON insert using ObjectID() and in my travels have found that this solution is not very good for indexing. The proposed solution has _id values that are strings rather than real object IDs - i.e. "56a970405ba22d16a8d9c30e" is different from ObjectId("56a970405ba22d16a8d9c30e") and indexing will be slower using the string. The ObjectId is actually represented internally as 16 bytes.

Andrei Todorut
  • 4,260
  • 2
  • 17
  • 28
cadaver
  • 47
  • 2