Given the following document structure:
{
'_id': ObjectId("559943fcda2485a66285576e"),
'user': '70gw3',
'data': [
{
'date': ISODate("2015-06-29T00:00:00.0Z"),
'clicks': 1,
},
{
'date': ISODate("2015-06-30T00:00:00.0Z"),
'clicks': 5,
},
]
}
How can I increment the clicks
value of 2015-06-30
and increase if it doesn't exists [the whole document OR the specific date], make it equals to 1
?
Unfortunately it is not possible to achieve your goal within a single query. But instead you can do the following
var exists = db.yourCollection.find(
{'_id': ObjectId("559943fcda2485a66285576e"), 'data.date': <your date>}
).count()
This query will return the number of documents which have the specified _id
and an object with the specified date in the data
array. As the _id
field is unique, you will get at most one result. If such element does not exist in the data
array, you will not get any result. Thus, you have the following cases:
Then this can become your condition:
if (exists) {
db.yourCollection.update({_id: <your id>, 'data.date': <your date>}, {$inc: {'data.$.clicks': 1}})
} else {
if (db.runCommand({findAndModify: 'yourCollection', query: {_id: <your id>, 'data.date': {$ne: <your date>}}, update: {$push: {data: {date: <your date>, clicks: 1}}}}).value) {
db.yourCollection.update({_id: <your id>, 'data.date': <your date>}, {$inc: {'data.$.clicks': 1}})
}
}
The correct answer is that while you need to perform two update operations in order to fulfil the logic there is no need to find and check data in a way.
You have two basic conditions
The process is basically then two updates. One will succeed and the other will not. No need to check.
Probably the best way to implement this is using the "Bulk" operations API. This allows both update statements to be sent to the server at the same time, and the response it a single response so there are less trips. But the logic is the same even if you don't use this.
var bulk = db.collection.initializeOrderedBulkOp();
// Update the date where it matched
bulk.find({ "user": "70gw3", "data.date": new Date("2015-06-30") })
.updateOne({ "$inc": { "data.$.clicks": 1 } });
// Push a new element where date does not match
bulk.find({ "user": "70gw3", "data.date": { "$ne": new Date("2015-06-30") } })
.updateOne({ "$push": { "data": { "date": new Date("2015-06-30"), "clicks": 1 } }});
bulk.execute();
In short, out of two update requests sent for any document then only one of the operations will actually modify anything. This is because the conditions for testing "date" are the "inverse" of one another, in that you "update" where present, and "create" where the matching element is not present.
Both states cannot exist at the same time, as long as the "create" follows the "update" the logic is sound. So first try to update, and then try to "create" where no match is found.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With