Aggregate documents with diversity - mongodb

[
{
"_id": 0,
"type": "cat"
},
{
"_id": 1,
"type": "dog"
},
{
"_id": 2,
"type": "cat"
},
{
"_id": 3,
"type": "unicorn"
}
]
How to select N documents and preserve diversity based on the field type.
Examples:
If I request 2 documents, I should never have two documents of type
"cat"
If I request 4 documents, I should only have 3 (only one of
"type": "cat" should be included)

Related

Aggregate and match multiple subdocuments in mongoDB

So I have the following document structure:
{
"id": 0,
"users": [
{
"name": "bob",
"id": 1000
},
{
"name": "sally",
"id": 2000
}
],
"comments": [
{
"commentor_index": 0,
"comment": "foo",
"emoji": "smile"
},
{
"commentor_index": 0,
"comment": "bar",
"emoji": "heart"
},
{
"commentor_index": 1,
"comment": "zee",
"emoji": "heart"
}
]
}
The comments have the users index in the array.
I would like to be able to get how many comments each user id left across all documents.
I have gotten so far to realize I need to unwind both users and comments with includeArrayIndex for users, but I have trouble rejoining them.

Flutter - How to get if an object in a nested json list is contained in another nested json list

Nested list 1
{
"count": 0,
"Services": [
{
"Name": "Air",
"id": 1
},
{
"Name": "Road",
"id": 2
},
{
"Name": "Ship",
"id": 3
}
]
}
Nested List 2
{
"count": 0,
"TransportMeans": [
{
"Name": "Helicopter",
"serviceId": 1
},
{
"Name": "Car",
"serviceId": 2
}
]
}
Check whether the serviceId has already been set or given so that it should not accept duplicate values. If the id in list 1 is in list 2 then it should throw an error else build an Alertbox and the serviceId is related to the Id.

MongoDB nested array aggregation

I want to aggregate data for the following sample array.
[
{
"_id": "5b7c0540342100091a375793",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionThird",
"id": 2,
"value": [
10,
50,
20
]
}
]
}
]
},
{
"_id": "5b3cd546342100514b4683a2",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
19,
5,
8
]
},
{
"name": "sectionThird",
"id": 2,
"value": [
60
]
}
]
},
{
"name": "EFGH",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
5
]
},
{
"name": "sectionThsads",
"id": 2,
"value": [
8
]
}
]
}
]
}
]
I want the following output:
[
{
"page": "ABCD",
"sections": [
{
"name": "sectionThird",
"totalValue": 140
},
{
"name": "sectionFourth",
"totalValue": 32
}
]
},
{
"page": "EFGH",
"sections": [
{
"name": "sectionFourth",
"totalValue": 5
},
{
"name": "sectionThsads",
"totalValue": 8
}
]
}
]
In the above sample array, you can see there are multiple documents with "page" as one of the keys which are also an array of objects. Each page object has a key "name" which is going to be unique for each object in "page" array. The "page" object has "sections" key and they also have "name" key in them which is going to be unique for each object.
So the output array is grouped by page.name then in that its grouped by sections.name from all the page objects with the sum of all the value array throughout sections inside a page object with the same section name.
You can use below aggregation.
$unwind each page and section followed by $group with $sum to sum the values for each section and $push to push the sections values back into page array.
db.col.aggregate([
{"$unwind":"$pages"},
{"$unwind":"$pages.sections"},
{"$group":{
"_id":{"pagename":"$pages.name","sectionname":"$pages.sections.name"},
"totalTime":{"$sum":{"$sum":"$pages.sections.value"}}
}},
{"$group":{
"_id":"$_id.pagename",
"sections":{"$push":{"name":"$_id.sectionname","totalTime":"$totalTime"}}
}}])

MongoDB: Return deeply nested document from it's id regardless of level

I have a collection consisting of documents that are made up of an id, name and an array of items; the array in each document is supposed to nest other documents of the same structure when applicable, and there is no limit to how many nested arrays of documents there are (nested documents can also have nested documents).
Using the MongoClient package, I'm trying to query my collection and return a document based on it's id, regardless of it's location in the data (be it at the top level or 3 levels down).
So far I can return any top level data okay, but my query is not finding any nested data. I've seen similar questions where the data structure is limited and consistent, but as my data is dynamic and multi-layered, I haven't find a solution that fits this particular issue.
Here's my data:
[
{
"_id": 1,
"name": "Test 1",
"items": []
},
{
"_id": 2,
"name": "Test 2",
"items": [
{
"_id": 3,
"name": "Test 3",
"items": []
},
{
"_id": 4,
"name": "Test 4",
"items": [
{
"_id": 6,
"name": "Test 6",
"items": []
}
]
}
]
},
{
"_id": 5,
"name": "Test 5",
"items": []
}
]
Here's my Mongo query:
MongoClient.connect(connString, function(err, db) {
var collection = db.collection('items');
collection.findOne({_id: ObjectID("4")}, function(err, result) {
console.log(result);
});
db.close();
});
And result is intended to return the following, but returns null instead:
{
"_id": 4,
"name": "Test 4",
"items": [
{
"_id": 6,
"name": "Test 6",
"items": []
}
]
}
Can anyone share a solution as to how I can retrieve my data as intended?
It is not possible to query an infinate amount of document of documents due to the change of properties at each level. See Query Selectors (https://docs.mongodb.com/manual/reference/operator/query/#query-selectors) for a list of selectors that can be used.
However if it's possbile to limit or give a depth limit on the items then you could use a query such as:-
db.col.find( {$or: [ { "_id" : id }, { "items._id" : id }, { "items.items._id" : id }, { "items.items.items._id" : id } ] } );
If it's not possible to give a depth limit I'd advise re-modeling the document in to something like:
[
{
"_id": 1,
"name": "Test 1"
},
{
"_id": 3,
"name": "Test 3",
"parentId": 2
},
{
"_id": 6,
"name": "Test 6",
"parentId": 4
},
{
"_id": 4,
"name": "Test 4",
"parentId": 2
},
{
"_id": 2,
"name": "Test 2",
},
{
"_id": 5,
"name": "Test 5",
}
]
Then you could do a simple find by _id query:
> db.collection.find({_id: 4})
{ "_id" : 4, "name" : "Test 4", "parentId" : 2 }
If you also need to retain the document structure of the query you can use the $graphLookup aggregation stage.

mongo searching more than 1 collection for same criteria

I have a mongo DB with several collections that contain JSON document formats shown below:
{
"questions": [
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q1",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o1"
},
{
"type": 1,
"value": "o1"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes"
]
}
},
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q2",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o2"
},
{
"type": 1,
"value": "o2"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes",
"Glenn Rhee"
]
}
}
]
}
I'm able to search for questions.questionEntry.questionItem.theQuestion for a matching criteria with:
db.questions.find({"questions.questionEntry.questionItem.theQuestion" : "q1"},{'questions.$':1}).pretty()
This works well for the questions collection but how would I do the same search across multiple collections?
Many thanks
To use the same query across multiple collections you may have to use the JavaScript bracket notation to access the collections in a loop. For example, the following queries the records database for all the collections (using the db.getCollectionNames() command) with the specified query:
use records
var colls = db.getCollectionNames(), // get all the collections in records db
query = {"questions.questionEntry.questionItem.theQuestion" : "q1"},
projection = {"questions.$": 1};
colls.forEach(function (collection){
var docs = db[collection].find(query, projection).toArray(); // use the bracket notation
docs.forEach(function (doc){ printjson(doc); });
})
You will have to do this by yourself. There is no out-of-the-box support.
You can query MongoDB multi-threaded (depending on your programming language) and aggregate the results to a unified result.