Reputation: 5308
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
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
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