query find where element in array - mongodb

my documents "parents" got the folowing structure:
{childrenIdList: [23, 24, 34]}
{childrenIdList: [23, 88]}
{childrenIdList: [1, 5, 8]}
how to select parents by childId in there childrenIdList?
Such query must return first two documents of 3 in my example if childId = 23.
I tried to use elemMatch method, but seemingly it works only with objects, i.e. it would work only if my data would be {childrenIdList: [{Id: 1}, {Id: 5}, {Id: 8}]}

You can just use db.collection.find({childrenIdList: 23}). See the Query Arrays section in the manual for more details.

db.collection.find({"parent.childrenIdList": {$in: [23]}})

Related

MongoDB summing field of document during query

I want to execute a mongodb query that would fetch documents until the sum of a field of those documents exceeds a value. For example, if I have the following documents
{id: 1, qty: 40}
{id: 2, qty: 50}
{id: 3, qty: 30}
and I have a set quantity of 80, I would want to retrieve id1 and id2 because 40+50 is 90 and is now over 80. If I wanted a quantity of 90, I would also retrieve id1 and id2. Does anyone have any insight into how to query in this manner? (I'm using Go btw - but any general mongo query advice would help tremendously)
Since you're keeping a running sum of a certain field, the easiest way of doing this is running a Find operation, get a cursor, and iterate the cursor while keeping the sum yourself until the required total is reached. Then, close the cursor and return:
cursor, err:=coll.Find(context.Background(),query)
sum:=0
defer cursor.Close(context.Background())
for cursor.Next(context.Background()) {
cursor.Decode(&data)
sum+=data.Qty
if sum>=80 {
break
}
}

Distinct dict keys from array of dict

I am working on a project using MongoDB. I have so far managed to upload documents to the database. Records looks like
doc1 = {'customer_id': 1,
'order': "[{'item': 123, 'unit_price': 2.0}, \
{'item': 124, 'unit_price': 2.5}]"}
doc2 = {'customer_id': 2,
'order': "[{'item': 123, 'unit_price': 2.0}, \
{'item': 126, 'unit_price': 1.5}]"}
collection.insert(doc1)
collection.insert(doc2)
I would like to find distinct items from the collection. My attempt so far
db.collection.distinct("order.item")
Expected output:
[123,124,126]
This does not quite work since order is an array. I am looking for some way to unnest the array to get distinct item numbers. Eventually, I would like to get the count of those distinct items. Thanks for your help!
MongoDB does return distinct for nested items from an array of objects:
https://docs.mongodb.com/manual/reference/method/db.collection.distinct/#return-distinct-values-for-an-embedded-field
In your case db.collection.distinct("order.item") should return array of distinct items from orders collection

How to construct query to filter by pairs of keys in MongoDB?

let's assume that I have collection called my_collection, with three documents:
{'_id": 1, 'foo': 'foo_val', 'bar': 'bar_val'},
{'_id": 2, 'foo': 'foo_val2', 'bar': 'bar_val2'},
{'_id": 3, 'foo': 'foo_val', 'bar': 'bar_val2'}
I'd like to query it by given pairs of key-values, in this case e.g. I'd like to filter it by:
[{'foo': 'foo_val', 'bar': 'bar_val'}, {'foo': 'foo_val2', 'bar': 'bar_val2'}]
so it should return documents with ids 1 and 2.
It there an elegant way to do this in one call to db? I tried using the $in keyword, but it doesn't work as I want.
You'll want to use the $or operator:
db.your_collection.find({$or:[{'foo': 'foo_val', 'bar': 'bar_val'},{'foo': 'foo_val2', 'bar': 'bar_val2'}]})

MongoDB - Pagination based on non-unique fields

I am familiar with the best practice of range based pagination on large MongoDB collections, however I am struggling with figuring out how to paginate a collection where the sort value is on a non-unique field.
For example, I have a large collection of users, and there is a field for the number of times they have done something. This field is defintely non-unique, and could have large groups of documents that have the same value.
I would like to return results sorted by that 'numTimesDoneSomething' field.
Here is a sample data set:
{_id: ObjectId("50c480d81ff137e805000003"), numTimesDoneSomething: 12}
{_id: ObjectId("50c480d81ff137e805000005"), numTimesDoneSomething: 9}
{_id: ObjectId("50c480d81ff137e805000006"), numTimesDoneSomething: 7}
{_id: ObjectId("50c480d81ff137e805000007"), numTimesDoneSomething: 1}
{_id: ObjectId("50c480d81ff137e805000002"), numTimesDoneSomething: 15}
{_id: ObjectId("50c480d81ff137e805000008"), numTimesDoneSomething: 1}
{_id: ObjectId("50c480d81ff137e805000009"), numTimesDoneSomething: 1}
{_id: ObjectId("50c480d81ff137e805000004"), numTimesDoneSomething: 12}
{_id: ObjectId("50c480d81ff137e805000010"), numTimesDoneSomething: 1}
{_id: ObjectId("50c480d81ff137e805000011"), numTimesDoneSomething: 1}
How would I return this data set sorted by 'numTimesDoneSomething' with 2 records per page?
#cubbuk shows a good example using offset (skip) but you can also mould the query he shows for ranged pagination as well:
db.collection.find().sort({numTimesDoneSomething:-1, _id:1})
Since the _id here will be unique and you are seconding on it you can actually then range by _id and the results, even between two records having numTimesDoneSomething of 12, should be consistent as to whether they should be on one page or the next.
So doing something as simple as
var q = db.collection.find({_id: {$gt: last_id}}).sort({numTimesDoneSomething:-1, _id:1}).limit(2)
Should work quite good for ranged pagination.
You can sort on multiple fields in this case sort on numTimesDoneSomething and id field. Since id_ field is ascending in itself already according to the insertion timestamp, you will able to paginate through the collection without iterating over duplicate data unless new data is inserted during the iteration.
db.collection.find().sort({numTimesDoneSomething:-1, _id:1}).offset(index).limit(2)

Filtering query in MongoDB

I would like to create a filtering query for one of my collections in mongoDB. Basically I want to retrieve every element in my collection except some field in all the documents. On the mongoDB spec it's written something like this:
db.users.find({}, {thumbnail:0});
But I would like to do more, I would like to filter for three different entries, something more like this:
db.users.find({}, {thumbnail: 0, a: 0, b: 0});
The problem is that this is not working. I keep receiving those fields after the query.
I also tried something like this:
db.users.find({}, {{thumbnail: 0}, {a: 0}, {b: 0}});
But mongoDB doesn't even accept something like this...
Can anyone help me?
As I wrote in the comments of the question, I discovered that the guy that generated the collection gave me the wrong information about the data structure. The format of the collection is something like this: {_id: ..., "1" : {a : "a", b : "b", d : "d", ...}, ... } and so on, thus it's not possible to filter for example elements a and b from the collection when entirely retrieving it.