0

I'm trying to use MongoDB and mongoose for my little conversation app in where each user is having it's own collection but I'm getting an error when saving a new conversation:

ERROR: MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: chat.privatemessages.$id dup key: { : ObjectId('54f1a39ff467833f7e794636') }

My Schema:

    var chatPrivateMessagesSchema = mongoose.Schema({
    user: String,
    with:[{
        conversation_with: String,
        messages:[{
            text:String,
            created: {type: Date, default: Date.now}
        }]
    }]
});

var PrivateMessages = mongoose.model('PrivateMessages', chatPrivateMessagesSchema);

Method for saving new conversation:

socket.on ('chat', function (from, to, message, callback) {
    PrivateMessages.find ({}, function (err, users) {
        if (err) throw err;
        for (var i = 0; i < users.length; i++) {
            if (users[i].user == from) {
                var newPrivateMsg = new PrivateMessages ({_id: users[i]._id}, {
                    with: [{
                        conversation_with: to, //if conversation with "to" user does not exist create a new entry
                        messages: [{
                            text: message, //append a new message 
                            created: {type: Date, default: Date.now}
                        }]
                    }]
                });
                newPrivateMsg.save (function (err) {
                    if (err) throw err;
                });
            }
        }
    });
});

So basically the output I'm looking for should be something like this?

{
    "_id": "some id",
    "user": "John",
    "with": [{
        "conversation_with": "Maria",
        "_id": "some id",
        "messages": [{
            "text": "Hellomyfisrtmessage",
            "created": "somedate"
        }, {
            "text": "Secondmessage ",
            "created": "somedate"
        }, {
            "text": "Thirdmessage",
            "created": "somedate"
        }, ]
    }, {
        "conversation_with": "Peter",
        "_id": "some id",
        "messages": [{
                "text": "Hellomyfisrtmessage",
                "created": "somedate"
            }, {
                "text": "Secondmessage ",
                "created": "somedate"
            }, {
                "text": "Third message",
                "created": "some date"
            },

        ]
    }],

}

I'm really struggling how to insert a new entry :( Can anyone help please?

1 Answer 1

1

The issue is that you're setting every PrivateMessage _id to the user's _id, don't do that!

EDIT:

socket.on ('chat', function (from, to, message, callback) {
    PrivateMessages.find ({}, function (err, users) {
        if (err) throw err;
        for (var i = 0; i < users.length; i++) {
            if (users[i].user == from) {
                users[i].with.forEach(function(with){
                    if (with.conversation_with === to ){

                        // append new message
                        with.messages.push({
                            text: message,
                            created: { type: Date, default: Date.now }
                        })
                    }
                })

                users[i].save (function (err) {
                    if (err) throw err;
                });

            }
        }
    });
});
Sign up to request clarification or add additional context in comments.

5 Comments

thanks @Yuri , but your solution is adding a new entry each time for the same user. I need to keep the same entry for the same user and just add a new message for that particular person in conversation_with: to
So, your original question involved inserts, but what you actually want is an update, with a possible insert (if it doesn't exist?). I've updated my answer to show you how something like this could be done. But you'll likely have to modify it to include a condition where conversation_with does not match "to" , in which case you'd need to create one. I strongly suggest you simplify your schema, you do not need 2 nested arrays.
thanks so much @Yuri, this is what I needed. You're amazing. Although, I just realised that the schema might not be a best solution for storing the conversation between two people, as I'm saving only one persons messages, I then need to retrieve both users messages. I need to work on that. But anyway, thanks again.
btw, do you know of any good suitable schema for conversation between two people?
Its typically a good idea to simplify as much as possible. As for a conversation between two people, the 'conversation' is really an abstract idea symbolizing a collection of messages between two people, and can easily be modeled using queries. My schema would probably simply be { sender: ObjectId, recipient: ObjectId, message: String }. Where sender/recipient are ObjectId's lining to their respective user id's. Inserts become trivial (just call new and save). To find a conversation by user, just do a query where sender OR recipient == userid, followed by some basic array manipulation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.