I'm writing a procedure that will take an array of strings such as
var mywords = ["cat", "dog", "fish"]
and upsert them into a MongoDb collection (called the 'words' collection). I would like to keep a count of how many times each word has been inserted into the collection. It is possible that some of the words are already in the collection and some are not.
This works:
var my_func = function(mywords) {
//Get connection to db...
mywords.forEach(function(word) {
collection.update({name: word}, {$inc: {count: 1}}, {upsert: true});
});
}
Awesome. So now if {name: dog, count: 3} was the only document in the collection and I run my_func(["cat", "dog", "fish"]), then the collection will now contain:
{name: dog, count: 4, _id: blah}
{name: cat, count: 1, _id: blah}
{name: fish, count: 1, _id: blah}
This is exactly what I want except I would like to do this all in one update, ie. not within a forEach. I tried this:
var broken_func = function(mywords) {
//Get connection to db...
collection.update({name: {$in : {mywords}}, {$inc: {count: 1}}, {upsert: true, multi:true});
}
However, if I start with the same collection which only contains {name: dog, count: 3} and run my_func(["cat", "dog", "fish"]), my collection looks like this:
{name: dog, count: 3}
{count: 1}
I want MongoDb to match the name field of a document with any string in the mywords array and increment the count field of that document. If there is no document name field equal to some string in mywords, create a document {name: "stringFrom_mywords", count:1}.
Is what I want to do possible and how can I achieve the behavior I want? I feel that using forEach and doing separate updates is inefficient. I happen to be using the node.js MongoDb driver if you find that information useful. I am aware that my problem is similar to this ruby question Upsert Multiple Records with MongoDb