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

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 }
}
]
}
}

Related

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

What wrong with my mongo query to get a specific by nest document?

{
"_id" : ObjectId("5dbdacc28cffef0b94580dbd"),
"owner" : {
"image" : "https://lh3.googleusercontent.com/a-/AAuE7mCpG2jzbEdffPgdeVWnkBKwyzCCwEB1HMbU1LAVAg=s50",
"fullname" : "soeng kanel",
"userID" : "5da85558886aee13e4e7f044"
},
"image" : "soeng kanel-1572711618984.png",
"body" : "sdadadasdsadadas sds",
"date" : ISODate("2019-11-02T16:20:05.558Z"),
"comments" : [
{
"user" : "5da85558886aee13e4e7f044",
"fullname" : "soeng kanel",
"username" : "",
"comment" : "sdsfdsfdsfds",
"_id" : ObjectId("5dbdacc78cffef0b94580dbf"),
"replies" : [
{
"likes" : [
"5da85558886aee13e4e7f044"
],
"date" : ISODate("2019-11-02T16:20:05.558Z"),
"_id" : ObjectId("5dbdacd78cffef0b94580dc0"),
"reply" : "r1111111",
"username" : "",
"fullname" : "soeng kanel",
"user" : "5da85558886aee13e4e7f044"
},
{
"likes" : [],
"date" : ISODate("2019-11-02T16:20:05.558Z"),
"_id" : ObjectId("5dbdacdb8cffef0b94580dc1"),
"reply" : "r222222",
"username" : "",
"fullname" : "soeng kanel",
"user" : "5da85558886aee13e4e7f044"
},
{
"likes" : [],
"date" : ISODate("2019-11-03T03:04:23.528Z"),
"_id" : ObjectId("5dbe4749fa751f05afcc1bd6"),
"reply" : "33333333",
"username" : "",
"fullname" : "soeng kanel",
"user" : "5da85558886aee13e4e7f044"
}
],
"date" : ISODate("2019-11-02T16:20:05.558Z"),
"likes" : []
}
],
"likes" : [
"5da85558886aee13e4e7f044"
],
"project" : {},
"__v" : 2
}
My query is
db.getCollection("posts").aggregate([
{ $match: {_id: ObjectId("5dbdacc28cffef0b94580dbd"), "comments._id": ObjectId("5dbdacc78cffef0b94580dbf") }},
{ $unwind: "$comments"},
{ $match: { "comments._id": ObjectId("5dbdacc78cffef0b94580dbf")}},
{ $project: {"replies": "$comments.replies", _id: 0}},
{ $match: { "replies._id": ObjectId("5dbdacd78cffef0b94580dc0")}},
{ $project: {"likes": "$replies.likes", _id: 0}},
])
With this query I get 3 elements ,
{
"likes" : [
[
"5da85558886aee13e4e7f044"
],
[],
[]
]
}
That is not what I want, what I want is to get by specific
replies by this _id 5dbdacd78cffef0b94580dc0.
And My expectation
{
"likes" : [
[
"5da85558886aee13e4e7f044"
]
]
}
Try using $unwind on replies before you $match stage on replies.
db.collection.aggregate([
{
$match: {
_id: ObjectId("5dbdacc28cffef0b94580dbd"),
"comments._id": ObjectId("5dbdacc78cffef0b94580dbf")
}
},
{
$unwind: {
path: "$comments",
preserveNullAndEmptyArrays: false
}
},
{
$match: {
"comments._id": ObjectId("5dbdacc78cffef0b94580dbf")
}
},
{
$project: {
"replies": "$comments.replies",
_id: 0
}
},
{
$unwind: {
path: "$replies",
preserveNullAndEmptyArrays: false
}
},
{
$match: {
"replies._id": ObjectId("5dbdacd78cffef0b94580dc0")
}
},
{
$project: {
"likes": "$replies.likes"
}
}
])
Above query produce output in the following fashion:
[
{
"likes": [
"5da85558886aee13e4e7f044"
]
}
]
I hope that's okay.

Match documents with their inner array element variables in MongoDB

I can't understand how to compare a document variable to another document variable. My goal is to match all Authors who have at least one book written in their mothertongue (native language).
However, after unwinding the books array, My $match: { mothertongue: "$bookLang"}} doesn't return return anything, eventhough they're the same in the $project stage.
Can you help me without javascript?
This is my current query:
db.author.aggregate([
{
$unwind: "$books"
},
{
$project: {
books: true,
mothertongue: true,
bookLang: "$books.lang"
}
},
{
$match: { mothertongue: "$bookLang"}
}
])
And here is a sample of the dataset
{
"_id" : ObjectId("5aa7b34a338571a7470be0eb"),
"fname" : "Minna",
"lname" : "Canth",
"mothertongue" : "Finnish",
"birthdate" : ISODate("1844-03-19T00:00:00Z"),
"deathdate" : ISODate("1897-05-12T00:00:00Z"),
"books" : [
{
"title" : "Anna Liisa",
"lang" : "Finnish",
"language" : "finnish",
"edition" : 1,
"cover" : "Hard",
"year" : 1895,
"categorytags" : [
"Finland"
],
"publisher" : [
{
"name" : "Tammi",
"pubId" : ObjectId("5aa7b34a338571a7470be0e4")
}
]
},
{
"title" : "The Burglary and The House of Roinila",
"lang" : "English (UK)",
"translator" : ObjectId("5aa7b34a338571a7470be0ee"),
"cover" : "Soft",
"year" : 2010,
"categorytags" : [
"Finland"
],
"publisher" : [
{
"name" : "Jonathan Cape",
"pubId" : ObjectId("5aa7b34a338571a7470be0e7")
}
]
},
{
"title" : "Anna Liisa 2 ed.",
"lang" : "Finnish",
"language" : "finnish",
"edition" : 2,
"cover" : "hard",
"year" : 1958,
"categorytags" : [
"Finland"
],
"publisher" : [
{
"name" : "Otava",
"pubId" : ObjectId("5aa7b34a338571a7470be0e9")
}
]
}
]
}
End goal. note I'm not interested in formatting just yet, just the filtering
{
"Author" : "Charles Bukowski",
"BooksInMothertongue" : [
"Love Is a Dog from Hell"
]
}
{
"Author" : "Minna Canth",
"BooksInMothertongue" : [
"Anna Liisa",
"Anna Liisa 2 ed."
]
}
...
Try this
db.author.aggregate([{
$match: {
books: {
$ne: []
}
}
},
{
$project: {
books: {
$filter: {
input: "$books",
as: "book",
cond: {
$eq: ["$$book.lang", "$mothertongue"]
}
}
},
fname: 1
}
}, {
$unwind: "$books"
},
{
$group: {
_id: "$_id",
Author: {
$first: '$fname'
},
BooksInMothertongue: {
$push: "$books.title"
}
}
}
])

Possible query with MongoDB

I have this collection
[{
"_id" : ObjectId("57a8a6c3c48933256cfd8368"),
"Title" : "T1",
"TitleData" : [
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9b"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96fa7"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96f96"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9c"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9d"),
"Res" : 0
}
]
},
{
"_id" : ObjectId("57a8a6c3c48933256cfd8369"),
"Word" : "T2",
"WordsData" :
[
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9b"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96f96"),
"Res" : 2
}
]
},
{
"_id" : ObjectId("57a8a6c3c48933256cfd8360"),
"Word" : "T3",
"WordsData" :
[
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9b"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96fa7"),
"Res" : 0
}
]
}
]
I need to make a query to extract only documents which:
a) Contains in TitleData UserId = "57a87f5cc48933119cb96f9b" AND "57a87f5cc48933119cb96fa7"
b) At least one of the 2 TitleData element must have MatchType != 2
So the final result will be:
[{
"_id" : ObjectId("57a8a6c3c48933256cfd8360"),
"Title" : "T3",
"TitleData" :
[
{
"UserId" : ObjectId("57a87f5cc48933119cb96f9b"),
"Res" : 2
},
{
"UserId" : ObjectId("57a87f5cc48933119cb96fa7"),
"Res" : 0
}
]
}
]
What i can do, is filter results for the a) criteria with the following instruction:
db.getCollection('collection_name').find({TitleData:{$elemMatch:{UserId:ObjectId("57a87f5cc48933119cb96f9b"),UserId:ObjectId("57a87f5cc48933119cb96fa7")}}})
but i can't find a way to filter with the b) condition in AND with a).
Any suggestion?
[EDIT]
This solution works better for point a).
db.getCollection('collection_name').find({
$and: [{
TitleData: {
$elemMatch: {
UserId: ObjectId("57a87f5cc48933119cb96f9b")
}
}
},{
TitleData: {
$elemMatch: {
UserId: ObjectId("57a87f5cc48933119cb96fa7")
}
}
},
{
TitleData: {
$elemMatch: {
$ne: {
"Res": 2
}
}
}
}]
}));
Use $and:
db.getCollection('collection_name').find({
$and: [{
TitleData: {
$elemMatch: {
UserId: ObjectId("57a87f5cc48933119cb96f9b"),
UserId: ObjectId("57a87f5cc48933119cb96fa7")
}
}
}, {
TitleData: {
$elemMatch: {
$ne: {
"Res": 2
}
}
}
}]
}));
Test output from console with your collection objects:
> db.collection.find({ $and: [{ TitleData: { $elemMatch: { UserId: ObjectId("57a87f5cc48933119cb96f9b"), UserId: ObjectId("57a87f5cc48933119cb96fa7") } } },{ TitleData: { $elemMatch: { $ne: { "Res": 2 } } }}]});
{ "_id" : ObjectId("57a8a6c3c48933256cfd8368"), "Title" : "T1", "TitleData" : [ { "UserId" : ObjectId("57a87f5cc48933119cb96f9b"), "Res" : 2 }, { "UserId" : ObjectId("57a87f5cc48933119cb96fa7"), "Res" : 2 }, { "UserId" : ObjectId("57a87f5cc48933119cb96f96"), "Res" : 2 }, { "UserId" : ObjectId("57a87f5cc48933119cb96f9c"), "Res" : 2 }, { "UserId" : ObjectId("57a87f5cc48933119cb96f9d"), "Res" : 0 } ] }
EDIT Didn't add all of console output...

mongodb aggregation $group and then $push a object

this is my data :
> db.bookmarks.find({"userId" : "56b9b74bf976ab70ff6b9999"}).pretty()
{
"_id" : ObjectId("56c2210fee4a33579f4202dd"),
"userId" : "56b9b74bf976ab70ff6b9999",
"items" : [
{
"itemId" : "28",
"timestamp" : "2016-02-12T18:07:28Z"
},
{
"itemId" : "29",
"timestamp" : "2016-02-12T18:07:29Z"
},
{
"itemId" : "30",
"timestamp" : "2016-02-12T18:07:30Z"
},
{
"itemId" : "31",
"timestamp" : "2016-02-12T18:07:31Z"
},
{
"itemId" : "32",
"timestamp" : "2016-02-12T18:07:32Z"
},
{
"itemId" : "33",
"timestamp" : "2016-02-12T18:07:33Z"
},
{
"itemId" : "34",
"timestamp" : "2016-02-12T18:07:34Z"
}
]
}
I want to have something like (actually i hope the _id can become userId too) :
{
"_id" : "56b9b74bf976ab70ff6b9999",
"items" : [
{ "itemId": "32", "timestamp": "2016-02-12T18:07:32Z" },
{ "itemId": "31", "timestamp": "2016-02-12T18:07:31Z" },
{ "itemId": "30", "timestamp": "2016-02-12T18:07:30Z" }
]
}
What I have now :
> db.bookmarks.aggregate(
... { $match: { "userId" : "56b9b74bf976ab70ff6b9999" } },
... { $unwind: '$items' },
... { $sort: { 'items.timestamp': -1} },
... { $skip: 2 },
... { $limit: 3},
... { $group: { '_id': '$userId' , items: { $push: '$items.itemId' } } }
... ).pretty()
{ "_id" : "56b9b74bf976ab70ff6b9999", "items" : [ "32", "31", "30" ] }
i tried to read the document in mongo and find out i can $push, but somehow i cannot find a way to push such object, which is not defined anywhere in the whole object. I want to have the timestamp also.. but i don't know how should i modified the $group (or others??) to do so. thanks for helping!
This code, which I tested in the MongoDB 3.2.1 shell, should give you the output format that you want:
> db.bookmarks.aggregate(
{ "$match" : { "userId" : "Ursula" } },
{ "$unwind" : "$items" },
{ "$sort" : { "items.timestamp" : -1 } },
{ "$skip" : 2 },
{ "$limit" : 3 },
{ "$group" : { "_id" : "$userId", items: { "$push" : { "myPlace" : "$items.itemId", "myStamp" : "$items.timestamp" } } } } ).pretty()
Running the above will produce this output:
{
"_id" : "Ursula",
"items" : [
{
"myPlace" : "52",
"myStamp" : ISODate("2016-02-13T18:07:32Z")
},
{
"myPlace" : "51",
"myStamp" : ISODate("2016-02-13T18:07:31Z")
},
{
"myPlace" : "50",
"myStamp" : ISODate("2016-02-13T18:07:30Z")
}
]
}
In MongoDB version 3.2.x, you can also use the $out operator in the very last stage of the aggregation pipeline, and have the output of the aggregation query written to a collection. Here is the code I used:
> db.bookmarks.aggregate(
{ "$match" : { "userId" : "Ursula" } },
{ "$unwind" : "$items" },
{ "$sort" : { "items.timestamp" : -1 } },
{ "$skip" : 2 },
{ "$limit" : 3 },
{ "$group" : { "_id" : "$userId", items: { "$push" : { "myPlace" : "$items.itemId", "myStamp" : "$items.timestamp" } } } },
{ "$out" : "ursula" } )
This gives me a collection named "ursula":
> show collections
ursula
and I can query that collection:
> db.ursula.find().pretty()
{
"_id" : "Ursula",
"items" : [
{
"myPlace" : "52",
"myStamp" : ISODate("2016-02-13T18:07:32Z")
},
{
"myPlace" : "51",
"myStamp" : ISODate("2016-02-13T18:07:31Z")
},
{
"myPlace" : "50",
"myStamp" : ISODate("2016-02-13T18:07:30Z")
}
]
}
>
Last of all, this is the input document I used in the aggregation query. You can compare this document to how I coded the aggregation query to see how I built the new items array.
> db.bookmarks.find( { "userId" : "Ursula" } ).pretty()
{
"_id" : ObjectId("56c240ed55f2f6004dc3b25c"),
"userId" : "Ursula",
"items" : [
{
"itemId" : "48",
"timestamp" : ISODate("2016-02-13T18:07:28Z")
},
{
"itemId" : "49",
"timestamp" : ISODate("2016-02-13T18:07:29Z")
},
{
"itemId" : "50",
"timestamp" : ISODate("2016-02-13T18:07:30Z")
},
{
"itemId" : "51",
"timestamp" : ISODate("2016-02-13T18:07:31Z")
},
{
"itemId" : "52",
"timestamp" : ISODate("2016-02-13T18:07:32Z")
},
{
"itemId" : "53",
"timestamp" : ISODate("2016-02-13T18:07:33Z")
},
{
"itemId" : "54",
"timestamp" : ISODate("2016-02-13T18:07:34Z")
}
]
}