Is there a way to update (or delete) many documents matching a certain criteria and get the list of IDs of actually updated/deleted documents (or some other fields of those documents)? I cannot simply query the documents matching my criteria beforehand because I need kinda atomicity for this operation. And I can't use findAndModify because it can only process one document at a time which is too slow because of round-trips. Suggestions?
MongoDB only supports atomic operations on a single document.
http://www.mongodb.org/display/DOCS/Atomic+Operations
The only way to do this is to do what you said you didn't one to:
First query the collection to find id's for our query:
db.things.find({"name":"john"}, {_id:1});
Then, use the same query to remove:
db.things.remove({"name":"john"}, {_id:1});
Not ideal, and not atomic, but it's as good as you're going to get in this scenario.
Related
I am trying to update many documents in a single query, how can I update many documents in a single query such that I don't have to loop over a list and update each individually?
You can create an array of operations that you want, and use a bulkWrite (view the docs here).
In that way you don't need to make a lot of request and get all the updates done. You can choose if you want the operations to be ordered or unordered and each type of operation has its own behavior. You can also choose which level of write concern you want.
Say I have a mongo $or query, something like { $or: [query1, query2, ... queryN] }, where each embedded query could be complex. Upon executing the query, a set of documents matching one or more of the embedded queries is returned. I would like to know which of the N embedded queries was satisfied for each document in the returned set, perhaps by adding a new field that I specify, eg. marks, into each returned document that would hold a list of the indexes of whichever of the queries was satisfied. I need this information to indicate how each document was identified in my application's interface.
I realize I could inspect the set once it is returned and determine the queries that were satisfied, but these queries could be arbitrarily complex and expensive to inspect - besides, this must have already been done inside mongo itself while doing the search.
I also realize I could run each of the N queries sequentially and then mark and merge the results into a growing set, but I want to save that overhead by running a single query instead of N queries.
And I realize that Mongo will certainly stop once the first satisfying query is found for each document, so I may not be able to get the complete set, but then I would at least like some assurance that the queries are executed in a certain order, say 1...N, and each document could be marked with its first satisfying index.
Does anyone know if there's a mechanism in Mongo that can do this?
You can use aggregation.
Use $addFields to add a new field for each query.
You could either $match first, and then add the fields, or add the fields first and on the added fields.
Currently I have a tree with various depth that contains user's documents.
John\folder1\sub-folder2...\document
Peter\folder1...\document
But as I can see Mongo does not support indexes in nested documents.
I tried to de-normalize my DB to User\documents with children ids. But it seems search would search whole collection, not only documents for given app-user.
should I create collection for every app user?
What is the better solution to use built in Mongo aggregation methods?
You need to use only one collection and not create collection for every user.
Using aggregation first thing you would do is a match by userId which filters all the documents by that user and then do any aggregation operations.
Aggregation in mongo is pipeline. Documents move from one operation to another.
So if you do match on userId then only those documents would be chosen and the next aggregation operation will get only those documents which matches the userId. So your aggregation is still faster.
This both operations delete one object. Is there any performance difference between them or both are same?
findOneAndDelete has the sort parameter which can be used to influence which document is updated. It also has a TimeLimit parameter which can control within which operation has to complete.
From the docs :
https://docs.mongodb.com/v3.2/reference/method/db.collection.findOneAndDelete/
Deletes a single document based on the filter and sort criteria,
returning the deleted document.
https://docs.mongodb.com/manual/reference/method/db.collection.deleteOne/
Removes a single document from a collection.
I'm doing multiple updates in a single bulk. Note: they are updates, not upserts. The problem doesn't allow it. Is there a way to find out which commands form the bulk matched (or didn't)?
From what I saw in the manual, you can only find the number of matches from BulkWriteResult, not which one matched, but I thought I'd ask anyway. Thanks for the help.
The BulkWriteResult doesn't contain this information and, as of MongoDB 2.6.3, there's no way to obtain it from the execution of the bulk operation. Of course, since you specify the criteria to determine which documents are updated, you can find out which documents are updated from the results of a find query with the same criteria. as long as the documents don't change in between. During a multistage bulk operation, you might change what documents match the update.