aggregation $unwind ,$lookup is not working in mongodb - mongodb

this is the query i have structured in mongo shell
db.vendormasters.aggregate([
{
'$match': {
status: 'active',
}
},
{ '$unwind': '$mappedToDealers'},
{
$lookup: {
from: "orders",
let: {
vendorId: "$_id",dealerId:'$mappedToDealers'
},
pipeline: [
{
$match: {
$and: [
{
$eq: [
"$vendorId",
"$$vendorId"
]
},
{
$eq: [
"$dealerId",
"$$dealerId"
]
}
]
}
}
], as: "orders"
}
},
{ '$unwind': '$orders' },
}]).pretty()
**the error message which i am getting in the shell is **
E QUERY [js] Error: command failed: {
"ok" : 0,
"errmsg" : "unknown top level operator: $eq",
"code" : 2,
"codeName" : "BadValue"
} : aggregate failed :
my collection structure is
//////collection 1 : vendorMasters///////////
{
"_id" : ObjectId("5e5642e32500b8273cbde3ac"),
"mappedToDealers" : [
ObjectId("5e1d82156a67173cb877f67d"),
ObjectId("5e5906dfc749dc4498033f7f")
],
"phoneNo" : 6#7159###,
"name" : "addedVendor8",
"address" : "Address6",
}
//////collection 2: orders///////////
{
"_id" : ObjectId("5e3a710af2657521e8c5668a"),
"date" : ISODate("2020-02-11T18:30:00Z"),
"order" : [
{
"_id" : ObjectId("5e3a710af2657521e8c5668c"),
"punchCount" : "###1",
"leavecCount" : 5,
},
{
"_id" : ObjectId("5e3a710af2657521e8c5668b"),
"punchCount" : "###1",
"leavecCount" : 5,
}
],
"vendorId" : ObjectId("5e5642e32500b8273cbde3ac"),
"dealerId" : ObjectId("5e1d82156a67173cb877f67d"),
}
{
"_id" : ObjectId("5e3a710af2657521e8c5668a"),
"date" : ISODate("2020-02-11T18:30:00Z"),
"order" : [
{
"_id" : ObjectId("5e3a710af2657521e8c5668c"),
"punchCount" : "###1",
"leavecCount" : 6,
},
{
"_id" : ObjectId("5e3a710af2657521e8c5668b"),
"punchCount" : "###1",
"leavecCount" : 2,
}
],
"vendorId" : ObjectId("5e5642e32500b8273cbde3ac"),
"dealerId" : ObjectId("5e5906dfc749dc4498033f7f"),
}
NOTE: there can be different vendorId's and different dealerId's in the documents if nothing matches then i should return an empty array , point out whats wrong in my query.my objective is find out all the orders from the orders collection which have matching vendorId & dealerId if it doesnot match than it shall return empty array

Your $match condition just contains a logical expression:
$match: { $and: [...] }
However, it must contain a query. Try this one:
$match: { $expr: { $and: [...] } }

Related

Facing a problem with the lookup in the second (student) table that matches all incoming output records mongodb aggregation

I'm facing a problem with the lookup in the second (student) table that matches all incoming output records of the first(test) table. I have two collections "tests" and "students". "Test" collection contains all school tests and the "student" table contains student's attended tests. Student table contains "pastTest"(test attended in past with status "pass" or "fail")array. I want to retrieve student who passed all incoming tests (we retrieve from the tests table)
test table: _id (primary ket)
student.pastTests.testId (need to match with test._id)
Test Document:
{
"_id" : ObjectId("5c9b5c1005729b2bf23f3290"),
"testDate" : {
"term" : 1,
"week" : 7
},
"retestDate" : {
"term" : 1,
"week" : 10
},
"testOrder" : "1.1",
"testDateScheduled" : true,
"retestDateScheduled" : true
}
Student Document:
{
"_id" : ObjectId("5c92dd994e8e6b2c1647d0d0"),
"completedYears" : [],
"firstName" : "Andrew",
"lastName" : "Jonhson",
"teacherId" : ObjectId("5bf36b1076696374e65feb4f"),
"yearGroup" : "0",
"schoolId" : 40001,
"currentTest" : ObjectId("5c9b5c1005729b2bf23f3290"),
"pastTests" : [
{
"_id" : ObjectId("5d3570645045863d373f6db1"),
"testId" : ObjectId("5c9b5c1005729b2bf23f3290"),
"status" : "pass"
},
{
"_id" : ObjectId("5d425af07708f5636c3bec1c"),
"testId" : ObjectId("5c9b5fc460e39c2c58e44109"),
"status" : "pass"
},
{
"_id" : ObjectId("5d5e54a875fab079f4d03570"),
"testId" : ObjectId("5c9b6492bb581c2ceb553fef"),
"status" : "fail"
},
],
"createdAt" : ISODate("2019-03-21T00:40:57.401Z"),
"updatedAt" : ISODate("2020-09-24T19:55:38.291Z"),
"__v" : 0,
"holdTests" : [],
"completedTests" : [],
"className" : "dd",
}
Query:
db.getCollection('tests').aggregate([
{
$match: {
yearGroup: '-1',
$or : [
{
$and: [
{'retestDateScheduled': true},
{ 'retestDate.term': { $lt: 4 } },
]
},
{
$and: [
{'testDateScheduled': true},
{ 'testDate.term': { $lt: 4 } },
]
}
]
}
},
{
$lookup: {
from: 'students',
let: {testId: '$_id', schoolId: 49014, yearGroup: '-1'},
pipeline: [
]
}
}
])
Note: Initial match query returns all tests of the term-1, now I have to retrieve students who passed in all tests of the term-1.
Lookup stage is pending - facing problem with lookup in second (student) table who match all incoming output records of first(test) collection
Thanks in advance !!
Try this:
db.tests.aggregate([
{
$match: {
// Your match condition
}
},
{
$group: {
_id: null,
term_1_testIds: { $push: "$_id" },
test_count: { $sum: 1 }
}
},
{
$lookup: {
from: "students",
let: { term_1_testIds: '$term_1_testIds', schoolId: 40001, totalTestCount: "$test_count" },
pipeline: [
{
$match: {
$expr: { $eq: ["$schoolId", "$$schoolId"] }
}
},
{ $unwind: "$pastTests" },
{
$match: {
"pastTests.status": "pass",
$expr: { $in: ["$pastTests.testId", "$$term_1_testIds"] }
}
},
{
$group: {
_id: "$_id",
firstName: { $first: "$firstName" },
yearGroup: { $first: "$yearGroup" },
schoolId: { $first: "$schoolId" },
currentTest: { $first: "$currentTest" },
passedTestCount: { $sum: 1 },
pastTests: { $push: "$pastTests" }
}
},
{
$match: {
$expr: { $eq: ["$passedTestCount", "$$totalTestCount"] }
}
}
],
as: "students"
}
}
]);
Output:
{
"_id" : null,
"term_1_testIds" : [
ObjectId("5c9b5c1005729b2bf23f3290"),
ObjectId("5c9b5fc460e39c2c58e44109"),
ObjectId("5c9b6492bb581c2ceb553fef")
],
"test_count" : 3,
"students" : [
{
"_id" : ObjectId("5c92dd994e8e6b2c1647d0d1"),
"firstName" : "Dheemanth",
"yearGroup" : "0",
"schoolId" : 40001,
"currentTest" : ObjectId("5c9b5c1005729b2bf23f3290"),
"passedTestCount" : 3,
"pastTests" : [
{
"_id" : ObjectId("5d3570645045863d373f6db1"),
"testId" : ObjectId("5c9b5c1005729b2bf23f3290"),
"status" : "pass"
},
{
"_id" : ObjectId("5d425af07708f5636c3bec1c"),
"testId" : ObjectId("5c9b5fc460e39c2c58e44109"),
"status" : "pass"
},
{
"_id" : ObjectId("5d5e54a875fab079f4d03570"),
"testId" : ObjectId("5c9b6492bb581c2ceb553fef"),
"status" : "pass"
}
]
}
]
}
This how my tests collection looks like
/* 1 createdAt:3/27/2019, 5:24:58 PM*/
{
"_id" : ObjectId("5c9b6492bb581c2ceb553fef"),
"name" : "Test 3"
},
/* 2 createdAt:3/27/2019, 5:04:28 PM*/
{
"_id" : ObjectId("5c9b5fc460e39c2c58e44109"),
"name" : "Test 2"
},
/* 3 createdAt:3/27/2019, 4:48:40 PM*/
{
"_id" : ObjectId("5c9b5c1005729b2bf23f3290"),
"name" : "Test 1"
}
This is how my students collection looks like:
/* 1 createdAt:3/21/2019, 6:10:57 AM*/
{
"_id" : ObjectId("5c92dd994e8e6b2c1647d0d1"),
"firstName" : "Dheemanth",
"yearGroup" : "0",
"schoolId" : 40001,
"currentTest" : ObjectId("5c9b5c1005729b2bf23f3290"),
"pastTests" : [
{
"_id" : ObjectId("5d3570645045863d373f6db1"),
"testId" : ObjectId("5c9b5c1005729b2bf23f3290"),
"status" : "pass"
},
{
"_id" : ObjectId("5d425af07708f5636c3bec1c"),
"testId" : ObjectId("5c9b5fc460e39c2c58e44109"),
"status" : "pass"
},
{
"_id" : ObjectId("5d5e54a875fab079f4d03570"),
"testId" : ObjectId("5c9b6492bb581c2ceb553fef"),
"status" : "pass"
}
]
},
/* 2 createdAt:3/21/2019, 6:10:57 AM*/
{
"_id" : ObjectId("5c92dd994e8e6b2c1647d0d0"),
"firstName" : "Andrew",
"yearGroup" : "0",
"schoolId" : 40001,
"currentTest" : ObjectId("5c9b5c1005729b2bf23f3290"),
"pastTests" : [
{
"_id" : ObjectId("5d3570645045863d373f6db1"),
"testId" : ObjectId("5c9b5c1005729b2bf23f3290"),
"status" : "pass"
},
{
"_id" : ObjectId("5d425af07708f5636c3bec1c"),
"testId" : ObjectId("5c9b5fc460e39c2c58e44109"),
"status" : "pass"
},
{
"_id" : ObjectId("5d5e54a875fab079f4d03570"),
"testId" : ObjectId("5c9b6492bb581c2ceb553fef"),
"status" : "fail"
}
]
}
Also:
In your first $match stage, $and operator is redundant inside $or array it should be like this:
{
$match: {
yearGroup: '-1',
$or: [
{
'retestDateScheduled': true,
'retestDate.term': { $lt: 4 }
},
{
'testDateScheduled': true,
'testDate.term': { $lt: 4 }
}
]
}
}

mongo query join- get total records as key from another collection

I have two collections:
quiz_customer_record collection
{
"_id" : ObjectId("5f6ec91cbf74d27430b9c24f"),
"quiz_id" : "5f3a33185a1cd35632b8c98c",
"user_id" : "5efae8bed5c5f06f30a057ff",
"name" : "ABC",
"qualification" : "ttt",
"time_required" : "0:13 Mins",
"questions_attempted" : 2,
"total_quiz_questions" : 2,
"attempt_date" : "2020-09-26T04:52:48.169Z"
}
/* 4 */
{
"_id" : ObjectId("5f6eca82bf74d27430b9c252"),
"quiz_id" : "5f3a33185a1cd35632b8c98c",
"user_id" : "5f6ec9ba3b502398598a5ade",
"name" : "Test",
"qualification" : "BSC",
"time_required" : "0:6 Mins",
"questions_attempted" : 2,
"total_quiz_questions" : 2,
"attempt_date" : "2020-09-26T04:58:46.060Z"
}
dummy collection
/* 1 */
{
"_id" : ObjectId("5f6ec906bf74d27430b9c24d"),
"user_id" : "5efae8bed5c5f06f30a057ff",
"question_id" : "5f6ec888bf74d27430b9c248",
"quiz_id" : "5f3a33185a1cd35632b8c98c",
"selected_answer" : [
"rgdfgdfg"
],
"attempt_date" : "2020-09-26T04:52:25.977Z",
"correct_answer" : [
"rgdfgdfg"
],
"result" : true
}
/* 2 */
{
"_id" : ObjectId("5f6eca82bf74d27430b9c250"),
"user_id" : "5f6ec9ba3b502398598a5ade",
"question_id" : "5f6ec888bf74d27430b9c248",
"quiz_id" : "5f3a33185a1cd35632b8c98c",
"selected_answer" : [
"rgdfgdfg"
],
"attempt_date" : "2020-09-26T04:58:46.060Z",
"correct_answer" : [
"rgdfgdfg"
],
"result" : true
}
/* 3 */
{
"_id" : ObjectId("5f6eca82bf74d27430b9c251"),
"user_id" : "5f6ec9ba3b502398598a5ade",
"question_id" : "5f6ec8b4bf74d27430b9c24b",
"quiz_id" : "5f3a33185a1cd35632b8c98c",
"selected_answer" : [
"sdfsdf"
],
"attempt_date" : "2020-09-26T04:58:46.060Z",
"correct_answer" : [
"sdfsdf"
],
"result" : true
}
From the 2nd(dummy collection i want the total records per user)
I am using this query in which i need modifications:
db.quiz_customer_record.aggregate([{ $match: { quiz_id:"5f3a33185a1cd35632b8c98c"}},
{
$sort: { attempt_date: -1 }
},
{
$group: {
_id: "$user_id",
result1: { $first: "$attempt_date" },
quiz_id: { $first: "$quiz_id" },
o_id: { $first: "$_id" }
}
},
{
$project: {
_id: "$o_id",
user_id: "$_id",
result1: 1
}
}
])
this will give the result as:
/* 1 */
{
"attempt_date" : "2020-09-26T04:52:48.169Z",
"_id" : ObjectId("5f6ec91cbf74d27430b9c24f"),
"user_id" : "5efae8bed5c5f06f30a057ff"
}
/* 2 */
{
"attempt_date" : "2020-09-26T04:58:46.060Z",
"_id" : ObjectId("5f6eca82bf74d27430b9c252"),
"user_id" : "5f6ec9ba3b502398598a5ade"
}
Expected Result: (as per user_id I need the count of records from dummy collection where quiz_id and attempt_date(result1 from above query) matches)
/* 1 */
{
"attempt_date" : "2020-09-26T04:52:48.169Z",
"_id" : ObjectId("5f6ec91cbf74d27430b9c24f"),
"user_id" : "5efae8bed5c5f06f30a057ff",
"total_dummy_rec":0
}
/* 2 */
{
"attempt_date" : "2020-09-26T04:58:46.060Z",
"_id" : ObjectId("5f6eca82bf74d27430b9c252"),
"user_id" : "5f6ec9ba3b502398598a5ade",
"total_dummy_rec":2
}
where total_dummy_rec is the count of total record per user in "dummy" collection.
I am confused on how to approach so i can achieve this result. Help me find a solution. Thank you!
You can add 2 stages after your pipeline stages,
$lookup to join dummy collection, where pass required field in let and in pipeline match condition
moved $project at last and count total document in dummy using $size
{
$lookup: {
from: "dummy",
let: {
quiz_id: "$quiz_id",
user_id: "$_id",
attempt_date: "$attempt_date"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$$quiz_id", "$quiz_id"] },
{ $eq: ["$$user_id", "$user_id"] },
{ $eq: ["$$attempt_date", "$attempt_date"] }
]
}
}
}
],
as: "dummy"
}
},
{
$project: {
_id: "$o_id",
user_id: "$_id",
result1: 1,
total_dummy_rec: {
$size: "$dummy"
}
}
}
Playground

Partition data around a match query during aggregation

What I have been trying to get my head around is to perform some kind of partitioning(split by predicate) in a mongo query. My current query looks like:
db.posts.aggregate([
{"$match": { $and:[ {$or:[{"toggled":false},{"toggled":true, "status":"INACTIVE"}]} , {"updatedAt":{$gte:1549786260000}} ] }},
{"$unwind" :"$interests"},
{"$group" : {"_id": {"iid": "$interests", "pid":"$publisher"}, "count": {"$sum" : 1}}},
{"$project":{ _id: 0, "iid": "$_id.iid", "pid": "$_id.pid", "count": 1 }}
])
This results in the following output:
{
"count" : 3.0,
"iid" : "INT456",
"pid" : "P789"
}
{
"count" : 2.0,
"iid" : "INT789",
"pid" : "P789"
}
{
"count" : 1.0,
"iid" : "INT123",
"pid" : "P789"
}
{
"count" : 1.0,
"iid" : "INT123",
"pid" : "P123"
}
All good so far, but then I had realized that for the documents that match the specific filter {"toggled":true, "status":"INACTIVE"}, I would rather decrement the count (-1). (considering the eventual value can be negative as well.)
Is there a way to somehow partition the data after match to make sure different grouping operations are performed for both the collection of documents?
Something that sounds similar to what I am looking for is
$mergeObjects, or maybe $reduce, but not much that I can relate from the documentation examples.
Note: I can sense, one straightforward way to deal with this would be to perform two queries, but I am looking for a single query to perform the operation.
Sample documents for the above output would be:
/* 1 */
{
"_id" : ObjectId("5d1f7******"),
"id" : "CON123",
"title" : "Game",
"content" : {},
"status" : "ACTIVE",
"toggle":false,
"publisher" : "P789",
"interests" : [
"INT456"
],
"updatedAt" : NumberLong(1582078628264)
}
/* 2 */
{
"_id" : ObjectId("5d1f8******"),
"id" : "CON456",
"title" : "Home",
"content" : {},
"status" : "INACTIVE",
"toggle":true,
"publisher" : "P789",
"interests" : [
"INT456",
"INT789"
],
"updatedAt" : NumberLong(1582078628264)
}
/* 3 */
{
"_id" : ObjectId("5d0e9******"),
"id" : "CON654",
"title" : "School",
"content" : {},
"status" : "ACTIVE",
"toggle":false,
"publisher" : "P789",
"interests" : [
"INT123",
"INT456",
"INT789"
],
"updatedAt" : NumberLong(1582078628264)
}
/* 4 */
{
"_id" : ObjectId("5d207*******"),
"id" : "CON789",
"title":"Stack",
"content" : { },
"status" : "ACTIVE",
"toggle":false,
"publisher" : "P123",
"interests" : [
"INT123"
],
"updatedAt" : NumberLong(1582078628264)
}
What I am looking forward to as a result though is
{
"count" : 1.0, (2-1)
"iid" : "INT456",
"pid" : "P789"
}
{
"count" : 0.0, (1-1)
"iid" : "INT789",
"pid" : "P789"
}
{
"count" : 1.0,
"iid" : "INT123",
"pid" : "P789"
}
{
"count" : 1.0,
"iid" : "INT123",
"pid" : "P123"
}
This aggregation gives the desired result.
db.posts.aggregate( [
{ $match: { updatedAt: { $gte: 1549786260000 } } },
{ $facet: {
FALSE: [
{ $match: { toggle: false } },
{ $unwind : "$interests" },
{ $group : { _id : { iid: "$interests", pid: "$publisher" }, count: { $sum : 1 } } },
],
TRUE: [
{ $match: { toggle: true, status: "INACTIVE" } },
{ $unwind : "$interests" },
{ $group : { _id : { iid: "$interests", pid: "$publisher" }, count: { $sum : -1 } } },
]
} },
{ $project: { result: { $concatArrays: [ "$FALSE", "$TRUE" ] } } },
{ $unwind: "$result" },
{ $replaceRoot: { newRoot: "$result" } },
{ $group : { _id : "$_id", count: { $sum : "$count" } } },
{ $project:{ _id: 0, iid: "$_id.iid", pid: "$_id.pid", count: 1 } }
] )
[ EDIT ADD ]
The output from the query using the input data from the question post:
{ "count" : 1, "iid" : "INT123", "pid" : "P789" }
{ "count" : 1, "iid" : "INT123", "pid" : "P123" }
{ "count" : 0, "iid" : "INT789", "pid" : "P789" }
{ "count" : 1, "iid" : "INT456", "pid" : "P789" }
[ EDIT ADD 2 ]
This query gets the same result with different approach (code):
db.posts.aggregate( [
{
$match: { updatedAt: { $gte: 1549786260000 } }
},
{
$unwind : "$interests"
},
{
$group : {
_id : {
iid: "$interests",
pid: "$publisher"
},
count: {
$sum: {
$switch: {
branches: [
{ case: { $eq: [ "$toggle", false ] },
then: 1 },
{ case: { $and: [ { $eq: [ "$toggle", true] }, { $eq: [ "$status", "INACTIVE" ] } ] },
then: -1 }
]
}
}
}
}
},
{
$project:{
_id: 0,
iid: "$_id.iid",
pid: "$_id.pid",
count: 1
}
}
] )
[ EDIT ADD 3 ]
NOTE:
The facet query runs the two facets (TRUE and FALSE) on the same set of documents; it is like two queries running in parallel. But, there is some duplication of code as well as additional stages for shaping the documents down the pipeline to get the desired output.
The second query avoids the code duplication, and there are much lesser stages in the aggregation pipeline. This will make difference when the input dataset has a large number of documents to process - in terms of performance. In general, lesser stages means lesser iterations of the documents (as a stage has to scan the documents which are output from the previous stage).

Filter result after an unwind

I've got an aggregation with an unwind :
{
$unwind: { "path":"$contributions", preserveNullAndEmptyArrays:true}
},
Output :
contributions" : {
"_id" : ObjectId("5b4e0636d3befc00155ffb8e"),
"creationDate" : ISODate("2018-07-17T15:07:34.172+0000"),
"validationDate" : ISODate("2018-07-17T15:07:42.008+0000"),
},
contributions" : {
"_id" : ObjectId("5b4e0636d3befc00155ffb8e"),
"rejectionDate" : ISODate("2018-07-17T15:07:34.172+0000"),
"validationDate" : ISODate("2018-07-17T15:07:42.008+0000"),
},
Now I want to filter this result to show only result that doesn't have a rejectionDate. So in this example, it should show only one result.
I try to add a filter :
$filter: {
input: `$contributions`, as: 'item',
cond: { $and: [
{ $not: '$$item.rejectionDate' },
...dateRangeFilterHelper('$$item.contributionDate', period)
] }
}
But it doesn't work like that.
instead of $not you can use $exists operator. you might get the desired output. Also if you can post the sample dataset and desired output then it will help to write the complete query.
The following query can get us the expected output:
db.collection.aggregate([
{
$addFields:{
"contributions":{
$filter:{
"input":"$contributions",
"as":"contribution",
"cond":{
$eq:["$$contribution.rejectionDate", undefined]
}
}
}
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d7275c4eb1b7fdde7ea09e8"),
"contributions" : [
{
"_id" : ObjectId("5b4e0636d3befc00155ffb8e"),
"creationDate" : ISODate("2018-07-17T15:07:34.172Z"),
"validationDate" : ISODate("2018-07-17T15:07:42.008Z")
},
{
"_id" : ObjectId("5b4e0636d3befc00155ffb8e"),
"rejectionDate" : ISODate("2018-07-17T15:07:34.172Z"),
"validationDate" : ISODate("2018-07-17T15:07:42.008Z")
}
]
}
Output:
{
"_id" : ObjectId("5d7275c4eb1b7fdde7ea09e8"),
"contributions" : [
{
"_id" : ObjectId("5b4e0636d3befc00155ffb8e"),
"creationDate" : ISODate("2018-07-17T15:07:34.172Z"),
"validationDate" : ISODate("2018-07-17T15:07:42.008Z")
}
]
}

Group by array element in Mongodb

We have nested document and trying to group by array element. Our document structure looks like
/* 1 */
{
"_id" : ObjectId("5a690a4287e0e50010af1432"),
"slug" : [
"true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
],
"tags" : [
{
"id" : "59244aa6b1be5055278e9b5b",
"name" : "true crime",
"_id" : "59244aa6b1be5055278e9b5b"
},
{
"id" : "5924524db1be5055278ebd6e",
"name" : "Occult Museum",
"_id" : "5924524db1be5055278ebd6e"
},
{
"id" : "5a690f0fc1a72100110c2656",
"_id" : "5a690f0fc1a72100110c2656",
"name" : "murder mysteries"
},
{
"id" : "59244d71b1be5055278ea654",
"name" : "unsolved murders",
"_id" : "59244d71b1be5055278ea654"
}
]
}
We want to find list of all slugs group by tag name. I am trying with following and it gets result but it isn't accurate. We have hundreds of records with each tag but i only get few with my query. I am not sure what i am doing wrong here.
Thanks in advance.
// Requires official MongoShell 3.6+
db.getCollection("test").aggregate(
[
{
"$match" : {
"item_type" : "Post",
"site_id" : NumberLong(2),
"status" : NumberLong(1)
}
},
{$unwind: "$tags" },
{
"$group" : {
"_id" : {
"tags᎐name" : "$tags.name",
"slug" : "$slug"
}
}
},
{
"$project" : {
"tags.name" : "$_id.tags᎐name",
"slug" : "$_id.slug",
"_id" : NumberInt(0)
}
}
],
{
"allowDiskUse" : true
}
);
Expected output is
TagName Slug
----------
true crime "true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
"All records where tags true crime"
Instead of using slug as a part of _id you should use $push or $addToSet to accumulate them, try:
db.test.aggregate([
{
$unwind: "$tags"
},
{
$unwind: "$slug"
},
{
$group: {
_id: "$tags.name",
slugs: { $addToSet: "$slug" }
}
},
{
$project: {
_id: 1,
slugs: {
$reduce: {
input: "$slugs",
initialValue: "",
in: {
$concat: [ "$$value", ",", "$$this" ]
}
}
}
}
}
])
EDIT: to get comma separated string for slugs you can use $reduce with $concat
Output:
{ "_id" : "murder mysteries", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "Occult Museum", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "unsolved murders", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "true crime", "slugs" : ",10-most-infamous-american-murder- mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }