MongoDB: Count of matching nested array elements - mongodb

I've got a simple parent child object stored as a document in MongoDB. Something simplistic like Order/OrderItems. (Order has an array of OrderItem)
What I'd like to do is query for a count of Order Items where they meet a set of criteria.
Example: In Order "999" find out how many order items had a quantity of 3.
db.collection.find( {OrderId:999, "OrderItems.QuantityOrdered":3} ).count();
The way this query works is it returns "1" because if it matches at least one OrderItem inside the array it will return the count of Orders matched.
How can I query for how many "OrderItems" matched?:

There's no direct way of return this sort of count with an embedded document. With this sort of ad-hoc count, your best bet is to return the document and do the count from the application.
If you want to perform this kind of count for a large number of orders, you could use map-reduce, which will output the results to a new collection.

Related

What kind of index(es) would be best to create to be able to search by one field and sort by another

I have a big collection of many million records consisting of:
{
"id1":string,
"id2":string,
"correlation":number
}
Which represents the relationships between pairs of records.
I would like to be able to efficiently run such queries as
db.collection.find({id1: 1}).sort({correlation: -1})
So, getting records by field id1 and sorting them by correlation field (in the descending order).
What kind of index(es) would be the most appropriate for such scenario?
I think the solution is to create the compound index like the following:
db.collection.createIndex({"id1": 1, "correlation": -1})
In my case all the queries of the form
db.collection.find({id1: id}).sort({correlation: -1})
run almost instantaneously.

Query by position in mongodb collection

I need to fetch the document in a mongodb collection using its position. I know the position of the document inside the collection exactly but could not figure out a way to pull those documents from collection. Is there any way to achieve this?
db.daily.find({'_id': {'$in': 0,5,8}})
This is what i tried but _id is not inserted as 1,2,3... but it has some random num Eg:57d8fd62f2a9d913ba0d006d. Thanks in advance.
You can use skip and limit to query based on the position in the natural order
db.collection.find().skip(10).limit(1) // get 10th document in natural order
As the natural order link points out, the document order need not match the order that documents are inserted (with an exception for capped collections). If you use the default ObjectId as the _id field for your documents you can sort by _id to order based on insertion in the collection (up to the resolution of the timestamp in the ObjectId)
db.collection.find().sort([("_id",1)]).skip(10).limit(1) // get 10th document in inserted order
You may also consider using your own _id or adding a field to be able to sort on in order to query based on the position you define.

store documents in descending order(mongodb-insert)

I am trying to add and retrieve documents from collection.I went through mongodb manual and didn't find ways to add documents in descending order by date. Is it possible to add documents to collection in descending order by date while inserting the document as i don't want to query and return the top 50 documents.
TIA.
MongoDB does not guarantee the retrieval order of documents. Even if you insert them in descending order, there is no guarantee the records will be returned in this order. As suggested by BatScream you could add an descending index on your date field and the order your result when querying the data.

MongoDB $in not only one result in case of repeated elements

I need to get the users whose ids are contained in an array. For this i'm using the $in operator, however being this inside an aggregate operation, i'd like to get back a specific user all the time it's id is present in the array, not just one. For example:
The ids array is A=[a,b,c,b] and U(x) is user with id x
with users.find({_id:{$in:A}}) i get these users as result: U(a),U(b),U(c)
instead i'd like to get back the result: U(a),U(b),U(c),U(b)
so get the user back every time it's id appears.
I understand that $in is working as expected but does anyone have an idea on how can i achieve this?
Thanks
This isn't possible using a MongoDB query.
MongoDB's query engine iterates over the documents in a collection (or over an index if there's a useful one) and returns to you any documents that match your query, in the order it finds them. Whether b appears once, twice, or a hundred times in your query makes no difference: the document with _id of b matches the query and is returned once, when MongoDB finds it.
You can do a post-processing step in your programming language to repeat documents as many times as you want.

In Mongodb, how to retrieve the subset of an object that matches a condition?

What I'm trying to do:
Filter a field of a collection that matches a given condition. Instead of returning every item in the field (which is an array of items), I only want to see matched items.
Similar to
select items from test where items.histPrices=[10,12]
It is also similar to what's found on the mongodb website here: http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields
Here's what I have been trying:
db.test.save({"name":"record", "items":[{"histPrices":[10,12],"name":"stuff"}]})
db.test.save({"name":"record", "items":[{"histPrices":[10,12],"name":"stuff"},
{"histPrices":[12,13],"name":"stuff"},{"histPrices":[11,14],"name":"stuff"}]})
db.test.find({},{"name":1,"items.histPrices":[10, 12]})
It will return all the objects that have a match for items.histPrices:[10,12], including ALL of the items in items[]. But I don't want the ones that don't match the condition.
From the comments left on Mongodb two years ago, the solution to get only the items with that histPrices[10,12] is to do it with javascript code, namely, loop through the result set and filter out the other items.
I wonder if there's a way to do that with just the query.
Your find query is wrong
db.test.find({},{"name":1,"items.histPrices":[10, 12]})
Your condition statement should be in the first part of the find statement.In your query {} means fetch all documents similar to this sql
select items from test (no where clause)
you have to change your mongodb find to
db.test.find({"items.histPrices":[10, 12]},{"name":1})
make it work
since your items is an array and if you wanted to return only the matching sub item, you have to use positional operator
db.test.find({"items.histPrices":[10, 12]},{"name":1,'items.$':1})
When working with arrays Embedded to the Document, the best approach is the one suggested by Chien-Wei Huang.
I would just add another aggregation, with the $group (in cases the document is very long, you may not want to retrieve all its content, only the array elements) Operator.
Now the command would look like:
db.test.aggregate({$match:{name:"record"}},
{$unwind:"$items"},
{$match {"items.histPrices":[10, 12]}},
{$group: {_id: "$_id",items: {$push: "$items"}}});)
If you are interested to return only one element from the array in each collection, then you should use projection instead
The same kind of issue solved here:
MongoDB Retrieve a subset of an array in a collection by specifying two fields which should match
db.test.aggregate({$unwind:"$items"}, {$match:{"items.histPrices":[10, 12]}})
But I don't know whether the performance would be OK. You have to verify it with your data.
The usage of $unwind
If you want add some filter condition like name="record", just add another $march at first, ex:
db.test.aggregate({$match:{name:"record"}}, {$unwind:"$items"}, {$match:{"items.histPrices":[10, 12]}})
https://jira.mongodb.org/browse/SERVER-828
Get particular element from mongoDB array
MongoDB query to retrieve one array value by a value in the array