I am creating mongodb with aggregate in which it should join two table so I have used $lookup but query returning me empty array
here is my query
return userScoringModel.aggregate([
{
"$match": {
examId: new ObjectId(req.params.examId),
user_Id: new ObjectId(req.params.userId),
subject: subject,
correctMark: {$lt: 0}
}
},
{
$lookup: {
from: "examPortalQuestions",
localField: "questionId",
foreignField: "_id",
as: "question_text"
}
},
{
"$group": {
"_id": {chapter: '$chapter'},
"questionNumbers": {$push: "$questionNo"},
"question_text": {$push: '$question_text'}
}
},
{
"$project": {
"_id": 0,
"subject": {
"name": "$_id.subject",
"chapter": "$_id.chapter",
"questionNumber": "$questionNumbers",
"question": "$question_text"
}
}
}
]).exec()
and here is output
{
"subject": {
"chapter": "NUMBER TEST AND PAIR FINDING",
"questionNumber": [
"20"
],
"question": [
[]
]
}
},
sample collection
score table:
_id, examid, userid , questionId, chapter
objectId ObjectId ObjectId ObjectId (ref:'questiontable') XYZ
objectId ObjectId ObjectId ObjectId (ref:'questiontable') qwe
Question table :
_id, question,
ObjectId what is abc?
here I am getting question array empty
can someone suggest me how to archive it
thanks in advance
Related
How can make I lookup on in with productId and categoryId.
Below is the sample of JSON
"data": {
"status": 1,
"offerId": "634017ad34c7b3545bd47681",
"offerType": "buyOneGetOne",
"categoryId": [
"62de9b22dcafd44290ab03c1",
"62dfe695ec4d69cfeab0265d"
],
"productId": [
"633170230e88e2d859d15ee6",
"62de9d102b2b72f80eda7585",
"62de9d1e2b2b72f80eda7588"
],
"title": "Buy One Get One Deal ",
"description": "buy one get more",
"amountType": "amount",
"amount": 12341,
"startDate": "2022-10-04T06:43:39.000Z",
"endDate": "2022-10-08T06:43:39.000Z"
}
I'm going to assume that you are using ObjectId as _id in your categories and products collection. If I understood your question your document as the following minimal structure:
_id: '1',
data: {
...
}
So, you are looking for something like:
db.nameOfYourCollectionWithData.aggregate([{
$addFields: {
'data.categoryId': {
$map: {
input: '$data.categoryId',
'in': {
$toObjectId: '$$this'
}
}
},
'data.productId': {
$map: {
input: '$data.productId',
'in': {
$toObjectId: '$$this'
}
}
}
}
}, {
$lookup: {
from: 'categories',
localField: 'data.categoryId',
foreignField: '_id',
as: 'data.categoryId'
}
}, {
$lookup: {
from: 'products',
localField: 'data.productId',
foreignField: '_id',
as: 'data.productId'
}
}])
First, you have to convert your array ids into ObjectId. After do this, you can perform the lookup stages directly. If your document is 'data', just remove any reference to data in the aggregate pipeline.
If your _id in categories and products are string instead of ObjectId, just remove the $addFields stage, because is no longer neccessary.
I'm trying to get an element value based on a result _id in an aggregation.
This is the aggregation:
$project: {
_id: 0,
brand: "$_id",
"options": {
$mergeObjects: "$ram"
},
sum: {
$add: [
"$sm",
1
]
}
}
And I want brand to get the name from other collection named "brands" which looks like this
[
{
"_id": ObjectId("617b0dbacda6cbd1a0403f68"),
"SerialNumber": "45454234324",
"name": "hp"
},
{
"_id": ObjectId("617b0dbacda6cbd1a0403f69"),
"SerialNumber": "azazz5245454az",
"name": "asus"
}]
What I want to get is the name of brand using using its _id based on the result _id.
Using SQL its something like this:
Get brands.name where _id=brands._id
i managed to do it using $lookup
{
$lookup:
{
from: "brands",
localField: "brand",
foreignField: "_id",
as: "brand"
}
},
{
$set: {
brand: "$brand.brand"
}
},
Suppose you have the following documents in my collection:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"name": "Asset1"
"shapes":[
{
"_id": "5cf10fea4cb6352abcfe094b",
"shape":"square",
"color":"blue"
},
{
"_id": "5cf10fea4cb6352abcfe094c",
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"name": "Asset2"
"shapes":[
{
"_id": "5c7524f76792cf28f80793e3"
"shape":"square",
"color":"black"
},
{
"_id": "5c7524f76792cf28f80793e4"
"shape":"circle",
"color":"green"
}
]
}
}
I do not have problem in finding a particular color like this also it is working
Test.find(
{"shapes.color": "red"},
//Match the exact color
{
products: {
$elemMatch: { color: "red" }
}
}
)
The main problem is I want to add this Asset1 and take only color red not the whole array by referencing ObjectId("562e7c594c12942f08fe4192") it in test2 collection. How do I do this using Mongoose?
This is the Test2 Schema where I did referencing
const Test2Schema = new Schema({
anothername: String,
test1Shape: {
type: mongoose.Schema.Types.ObjectId,
ref: "Test"
},
});
Use the below query, it uses $unwind, $match , $lookup and $out
$unwind - To unwind the Shapes array
$match - To filter the matching color red records
$lookup - To lookup the matching documents in Test2 Collection
$out - To override the Test2 collection with the merged document
db.Test1.aggregate([
{
$unwind: "$shapes"
},
{
$match: {
"shapes.color": "red"
}
},
{
$lookup: {
from: "Test2",
localField: "_id",
foreignField: "_id",
as: "mergeResult"
}
},
{
$out: "Test2"
}
]);
i am struggling with a task, which it is I used two schemas
User Schema
{
"first_name": String,
"last_name":String,
"address": String
}
Employee schema
{
user:{
type: ObjectId,
ref: 'User'
},
gross_pay: String,
net_pay: String
tax: String,
}
Well, how can I search first_name using $regex in Employee Schema in this user referenced field? I tried in so many ways, can't get it. how can i resolve it? Thanks in advance
First Approach:
Using $lookup aggregation
Employee.aggregate([
{ "$lookup": {
"from": "users",
"let": { "user": "$user" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$user"] }}},
{ "$project": { "firstName": 1 }}
],
"as": "user"
}},
{ "$unwind": "$user" },
{ "$match": { "user.firstName": { "$regex": your_string, "$options": "i" }}}
])
But it is not the better approach as the $lookup stage is being applied to all the Employee documents and then $match to the users firstName makes the query bit slow.
Second Approach:
First find the users having firstName equal to the match string using $regex and then find the _id in the Employee collection.
const userIds = await (Users.find({ "firstName": { "$regex": your_string, "$options": "i" } })).map(user => user._id)
const employees = await Employee.find({ "user": { "$in": userIds }})
Third Approach:
Keep the single key firstName of the user schema in the employee schema
Employee schema
user: { type: ObjectId, ref: 'User' },
gross_pay: String,
net_pay: String
tax: String
firstName: String
and then use query directly
const userIds = await Employee.find({
"firstName": { "$regex": your_string, "$options": "i" }
})
I have a visits collection where I successfully count the number of visits per location
Visits model:
{
"_id": {
"$oid": "5a3969e2f4ea3e33ac5a523d"
},
"locationId": "5a395ccf210a1d35d0df4a58"
}
locationId above is of type 'Object' as I learned lookup localField and foreignField must be of same type
nodejs code =>
let sort = { "count": -1, "locationId": 1 };
Visit.aggregate([
{
$match:{
$and: [
{ accountId: req.session.passport.user },
{
'details.dateTimeIn': {
$gte: new Date(dateFrom), $lte: new Date(dateTo)
}
}
]
}
},
{
"$group": {
//_id: name,
_id: "$locationId",
count: { $sum: 1 }
}
},
{ $sort: sort }
])
Output is half ok:
[
{
"_id":"5a395ccf210a1d35d0df4a58",
"count":20
}
]
Instead of showing location id id like to show location name. Schema for locations collection is:
{
"_id": {
"$oid": "5a395ccf210a1d35d0df4a58"
"name": "Tower A",
"__v": 0
}
}
Research suggests I need to use $lookup to get that JOIN effect
So I tried
{
"$lookup": {
from: "locations",
localField: "_id",
foreignField: "_id",
as: "locationdetails"
}
}
but the match seems broken. The closest I got was a list of all locations in 'locationdetails'
But with code above here is the empty locationdetails
[
{
"_id":"5a395ddf1d221918d0041313",
"count":20,
"locationdetails":[
]
}
]
What am I missing ?