Reputation: 3494
I want to use an array as a counter for documents that are associated with this document. Each array element corresponds to a document, and the number in that array corresponds to some piece of data about that document. These numbers are not stored with their associated documents so queries can be performed on the fields of the 'primary' document as well as the data in the array for the 'associated' documents.
Due to the vagaries of $inc and array initialization, there appears to be no way to do this:
> use foo
switched to db foo
> db.foo.save({id: []})
> db.foo.update({}, {$inc: {'id.4': 1}})
> db.foo.find().pretty()
{
"_id" : ObjectId("5279b3339a056b26e64eef0d"),
"id" : [
null,
null,
null,
null,
1
]
}
> db.foo.update({}, {$inc: {'id.2': 1}})
Cannot apply $inc modifier to non-number
Is there some way to increment a null or initialize the array with zeros?
An alternative is storing the array values in a key/value format which would therefore be a sparse array, but there's no way to upsert into an array, which makes that alternative infeasible.
Upvotes: 0
Views: 994
Reputation: 42352
While I'm not in favor of potentially unlimited in size arrays, there is a trick you can use to make the right thing happen here:
db.foo.insert({id:[]})
Whenever you increment a counter at index N, make sure you increment by 0 all indexes up to N.
db.foo.update({}, {$inc: {'id.0':0, 'id.1':0, 'id.2':0, 'id.3':0, 'id.4':1 } })
db.foo.update({}, {$inc: {'id.0':0, 'id.1':0, 'id.2':1 } })
db.foo.find()
{ "_id" : ObjectId("5279c8de0e05b308d0cf21ca"), "id" : [ 0, 0, 1, 0, 1 ] }
Upvotes: 2