Strange MongoDB $setIntersection behaviour - mongodb

I want to query a match between records in my db based on certain tags. The match would be calculated based on a formula and the intersection of the tags. Now, even querying the intersection doesn't work...always. Sometimes it does, sometimes it doesn't. In my example, if I change the displayName attribute to something else (add or remove one character, the query works. In its current state (for demo purposes) it doesn't as it does not deliver the one intersection match for the last doc with id 3.
https://mongoplayground.net/p/KAYPoV29RFO
That's my query:
db.collection.aggregate([
{
$match: {
"_id": "1"
}
},
{
"$lookup": {
from: "collection",
let: {
"criteria": "$tags"
},
pipeline: [
{
$project: {
"match": {
$setIntersection: [
"$tags",
"$$criteria"
]
},
}
}
],
as: "result"
}
},
{
$project: {
"tags": 0
}
},
])
Here is the example data (simplified):
[
{ "_id": "1", "tags": [{ "_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}, {"_id": "c", "displayName": "c", "level": 3}]},
{"_id": "2", "tags": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}]},
{"_id": "3", "tags": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "d", "displayName": "d", "level": 4}]}
]
and the result as it is: (expected is three matches for id 1, 2 matches for id 2 and one for the last id. However, the last result has 0 elements in the intersection result. Again, when i change "displayName" to "displayNam" or "displayNames" (obviously in all docs), it give the correct result...
[{
"_id": "1", "result": [
{"_id": "1", "match": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2},{"_id": "c","displayName": "c","level": 3}]},
{"_id": "2", "match": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}]},
{"_id": "3","match": [*here should be the match to _id: "a", but it's not (always) there*]}
]
}]
Does anyone have an idea what I am missing here?

Related

MongoDB: Graphlookup nested documents only returns single document in aggregation

I'm trying the MongoDB aggregation framework to work with nested documents but having trouble returning the expected output, specifically in the $graphLookup stage. In a non-nested schema, it correctly looks up all the documents as defined in the options and returns all. But in a nested one, it only returns one. I have tried $unwind and $replaceRoot as answered here but now it does not work. It would be more understandable through code so here are the samples.
Non-nested document (fileSystem does not count)
db={
"fileSystem": [
{
"_id": "a",
"label": "Root",
"children": [
"b",
],
},
{
"_id": "b",
"label": "Nested folder 1",
"children": [
"c",
"d",
"e"
],
"parent": "a"
},
{
"_id": "c",
"label": "Nested File 1.1",
"parent": "b"
},
{
"_id": "d",
"label": "Nested File 1.2",
"parent": "b"
},
]
}
// Aggregation Query
db.fileSystem.aggregate([
{
"$match": {
"_id": "a"
}
},
{
"$graphLookup": {
"from": "fileSystem",
"startWith": "$children",
"connectFromField": "children",
"connectToField": "_id",
"as": "nest",
"depthField": "level",
"maxDepth": 1
}
},
])
// correct and expected result
[
{
"_id": "a",
"children": [
"b"
],
"label": "Root",
"nest": [
{
"_id": "b",
"children": [
"c",
"d",
"e"
],
"label": "Nested folder 1",
"level": NumberLong(0),
"parent": "a"
},
{
"_id": "d",
"label": "Nested File 1.2",
"level": NumberLong(1),
"parent": "b"
},
{
"_id": "c",
"label": "Nested File 1.1",
"level": NumberLong(1),
"parent": "b"
}
]
}
]
Nested document and query
db={
"fileSystem": [
{
pp: [
{
"_id": "a",
"label": "Root",
"children": [
"b",
],
},
// ... same as previous
]
}
]
}
// Aggregation Query
db.fileSystem.aggregate([
{
"$unwind": "$pp"
},
{
"$replaceRoot": {
"newRoot": "$pp"
}
},
{
"$match": {
"_id": "a"
}
},
{
"$graphLookup": {
"from": "fileSystem",
"startWith": "$pp.children",
"connectFromField": "pp.children",
"connectToField": "pp._id",
"as": "nest",
"depthField": "level",
}
},
])
// incorrect result
[
{
"_id": "a",
"children": [
"b"
],
"label": "Root",
"nest": []
}
]
Expected: https://mongoplayground.net/p/A4yDGUHka58
Bugged: https://mongoplayground.net/p/ZlQyDBrYSZr
$graphLookup searches the collection given in from for matching documents. It uses each document in the pipeline as a starting point, but it does not search for, and will not return documents from the pipline.
In the sample data there is there is only 1 document, so the best you'll get in that case is for the next array to contain the original document.
Playground

MongoDb group by two conditions in aggregate

I would like to group my data by different conditions but I do not understand how I could do it.
My data:
[
{"Id": "1", "Info": "X" "Date": 10/1},
{"Id": "2", "Info": "X" "Date": 13/2},
{"Id": "3", "Info": "Y" "Date": 13/2},
{"Id": "4", "Info": "X" "Date": 10/1},
{"Id": "5", "Info": "X" "Date": 10/1},
{"Id": "6", "Info": "X" "Date": 13/2},
]
And I would like to group them by Info and by Date, a result similar to this one:
[
{"Id": ["1","4","5"], "Info": "X" "Date": 10/1},
]
[
{"Id": ["2", "6"], "Info": "X" "Date": 13/2},
]
[
{"Id": ["3"], "Info": "Y" "Date": 13/2},
]
I am using aggregate and I just know how to use aggregate to group them just by one condition, I donĀ“t know how to continue and how to use date in $group, this is what I have and how I group it by info:
.aggregate([
{ "$match" : { "$or": [{"status": "downloading"}, {"status": "calculating"}]}},
{ "$project": {"Id": 1, "Date": 1, "info": 1}},
{ "$group" : { "_id" : "$Info", "Id" : { "$addToSet" : "$Id"}}},
{ "$project": {"_id": 0, "Info": "$_id", "Id": 1 }}
You can give the _id in the $group stage multiple fields, like so:
db.collection.aggregate([
{
"$project": {
"Id": 1,
"Date": 1,
"info": 1
}
},
{
"$group": {
"_id": {
date: "$Date",
info: "$info"
},
"Id": {
"$addToSet": "$Id"
}
}
},
{
"$project": {
"_id": 0,
"Info": "$_id.info",
"Date": "$_id.date",
"Id": 1
}
}
])
Mongo Playground

mongodb: Query documents with average greater than a number

How do I find the documents with with average score greater than 5. The collection looks like this:
Collection restaurants:
{"grades": [{"grade": "A", "score": 2}, {"grade": "A", "score": 6}], "name": "Morris Park Bake Shop", "restaurant_id": "30075445"}
{"grades": [{"grade": "A", "score": 8}, {"grade": "B", "score": 23}], "name": "Wendy'S", "restaurant_id": "30112340"}
{"grades": [{"grade": "A", "score": 2}, {"grade": "A", "score": 11}], "name": "Dj Reynolds Pub And Restaurant", "restaurant_id": "30191841"}
I tried
db.restaurants.find({average_socre: {$gt: 5}}, {average_socre:{$avg: "$grades.score"}})
but it doesn't work.
Using this query:
db.collection.find({
$expr: {
$gt: [
{
"$avg": "$grades.score"
},
5
]
}
},
{
average_score: {
$avg: "$grades.score"
}
})
Live

mongodb map data in one collection

My intention is to map the reference column based on the id. This is my data in one collection.
[{
"title": "A",
"reference": ["2"],
"id": "1",
"author": ["Doraemon"]
},{
"title": "B",
"reference": [],
"id": "2",
"author": ["Naruto"]
}]
Does anyone can help me how to make it like this
[{
"title": "A",
"reference": ["B"],
"id": "1",
"author": ["Doraemon"]
},{
"title": "B",
"reference": [],
"id": "2",
"author": ["Naruto"]
}]
You can do self lookup
db.collection.aggregate([
{
"$lookup": {
"from": "collection",
"localField": "reference",
"foreignField": "id",
"as": "selfJoin"
}
},
{
$addFields: {
reference: "$selfJoin.title"
}
},
{
$project: {
selfJoin: 0
}
}
])
Working Mongo playground

Why is Robomongo returning an object from db.collection.distinct() instead of an array?

Using the example from the MongoDB reference, I'd expect db.inventory.distinct("dept"); to return an array ["A", "B"], and that's exactly what happens when I run this from the shell. Using Robomongo (on OS X) I instead get an object with name-value pairs, like so: { "0" :"A", "1": "B" }.
This is the setup:
db.inventory.drop();
db.inventory.insert([
{ "_id": 1, "dept": "A", "item": { "sku": "111", "color": "red" },
{ "_id": 2, "dept": "A", "item": { "sku": "111", "color": "blue" },
{ "_id": 3, "dept": "B", "item": { "sku": "222", "color": "blue" },
{ "_id": 4, "dept": "A", "item": { "sku": "333", "color": "black" }
]);
Why is Robomongo behaving different? Can I do anything about it?