Sathya
Sathya

Reputation: 5308

MongoDB - update documents in an array

UPDATE: I suggest to read my accepted answer, which gives you different approach on this problem.

I have following collection.

{
        "_id" : ObjectId("51fa56408e843042c0c24e3d"),
        "uniqDates" : [
                ISODate("2013-07-30T18:30:00Z"),
                ISODate("2013-07-31T18:30:00Z")
        ]
}
{
        "_id" : ObjectId("51fa5648c424ea3e37199502"),
        "events" : [
                {
                        "eid" : 1,
                        "title" : "Event 1",
                        "start" : ISODate("2013-08-04T18:30:00Z")
                },
                {
                        "eid" : 2,
                        "title" : "Event 2",
                        "start" : ISODate("2013-08-08T18:30:00Z")
                }
        ]
}

I want to update a document in "events" array if it exists (i want to check it by eid), if it doesn't exists i want to insert that document.

currently i am doing this with two queries.

db.col.update({events: {$exists: 1}}, {$pull: {"events": {"eid": 2}}});

and

db.schedule.update({events: {$exists: 1}}, {$addToSet: 
{"events": {"eid": 2, "title": "Event 4", "start": new Date(2013, 08, 02)}}});

Is there a way to do this with single query? Something with upsert operation.

Upvotes: 1

Views: 293

Answers (2)

Sathya
Sathya

Reputation: 5308

UPDATE
It is pretty obvious mindset to have collection like above to group documents. But having documents in array will result in some other problems. You have to suffer with Array Update operators to update each document. Instead, i restructured my collection as shown below. Also, see this google group discussion. As "idbentley" specified there is a possibility to exceed document size limit (16 MB) which will lead to data fragmentation. So be conscious while you model your data.

Original Answer

It seems like it is not possible to achieve upsert operation in document array. So changed my schema design like below.

{
        "_id" : ObjectId("51fa619a8e843042c0c24e46"),
        "uniqDates" : [
                ISODate("2013-07-30T18:30:00Z"),
                ISODate("2013-07-31T18:30:00Z")
        ]
}
{
        "_id" : ObjectId("51fa61b38e843042c0c24e47"),
        "eid" : 1,
        "title" : "Event 1",
        "start" : ISODate("2013-08-04T18:30:00Z")
}
{
        "_id" : ObjectId("51fa61b38e843042c0c24e48"),
        "eid" : 2,
        "title" : "Event 2",
        "start" : ISODate("2013-08-08T18:30:00Z")
}

To find events:

db.schedule.find({"eid": {$exists: 1}});

To find unique date:

db.schedule.find({"uniqDates": {$exists: 1}});

To achieve 'upsert' operation:

db.schedule.update({"eid": 3}, {"eid": 3, "title": "Event 3", 
                                "start": new Date(2013, 05, 06)}, true); 

This seems promising.

Upvotes: 0

Paul
Paul

Reputation: 811

I think you'll still need to do this with two queries. But, using a $ query to update, you can keep it to one query in the case where the EID already exists.

db.col.update({"events.eid": 2}}, {$set: {"events.$.title: "Event 4", "events.$.start": new Date(2013, 08, 02}})

If the return value from that indicates that no records were found, then you can insert it instead.

Upvotes: 1

Related Questions