MongoDB - join multiple collections - mongodb

I want to join (left) multiple collection:
Step1:
db.user.insertOne({
user_id: "id_user_1",
})
Step2: (add first document to each colection - id_user_1)
db.est_zone.insertOne({
zone: {
temp: "tempo1",
},
user_id: "id_user_1"
})
db.est_tax.insertOne({
tax: {
fam: "fam1",
},
user_id: "id_user_1"
})
Step3: (add second document to each colection - id_user_1)
db.est_zone.insertOne({
zone: {
temp: "tempo2",
},
user_id: "id_user_1"
})
db.est_tax.insertOne({
tax: {
fam: "fam2",
},
user_id: "id_user_1"
})
So, when i use $lookup (aggregate) with just one collection, it work like what i expect:
db.user.aggregate([
{
$match: {
user_id: "id_user_1"
}},
{
$lookup: {
from: "est_zone",
localField: "user_id",
foreignField: "user_id",
as: "est_zone"
}},
{$unwind: "$est_zone"},
])
output:
[
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1a68ef527b03093e78d5"
},
"zone": {
"temp": "tempo1"
},
"user_id": "id_user_1"
}
},
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1ad58c3dc65723ce0ac9"
},
"zone": {
"temp": "tempo2"
},
"user_id": "id_user_1"
}
}
]
tempo1 and tempo2 are in one document.
i expect fam1 in tempo1 document
and fam2 in tempo2 document
but, when i use lookup for join the "est_tax" it doesnt works like i want (even if use $unwind):
db.user.aggregate([
{
$match: {
user_id: "id_user_1"
}},
{
$lookup: {
from: "est_zone",
localField: "user_id",
foreignField: "user_id",
as: "est_zone"
}},
{$unwind: "$est_zone"},
{
$lookup: {
from: "est_tax",
localField: "user_id",
foreignField: "user_id",
as: "est_tax"
}},
])
output:
[
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1a68ef527b03093e78d5"
},
"zone": {
"temp": "tempo1"
},
"user_id": "id_user_1"
},
"est_tax": [
{
"_id": {
"$oid": "63db1a68ef527b03093e78d6"
},
"tax": {
"fam": "fam1"
},
"user_id": "id_user_1"
},
{
"_id": {
"$oid": "63db1ad58c3dc65723ce0aca"
},
"tax": {
"fam": "fam2"
},
"user_id": "id_user_1"
}
]
},
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1ad58c3dc65723ce0ac9"
},
"zone": {
"temp": "tempo2"
},
"user_id": "id_user_1"
},
"est_tax": [
{
"_id": {
"$oid": "63db1a68ef527b03093e78d6"
},
"tax": {
"fam": "fam1"
},
"user_id": "id_user_1"
},
{
"_id": {
"$oid": "63db1ad58c3dc65723ce0aca"
},
"tax": {
"fam": "fam2"
},
"user_id": "id_user_1"
}
]
}
]
What i expect:
[
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1a68ef527b03093e78d5"
},
"zone": {
"temp": "tempo1"
},
"user_id": "id_user_1"
},
"est_tax": [
{
"_id": {
"$oid": "63db1a68ef527b03093e78d6"
},
"tax": {
"fam": "fam1"
},
"user_id": "id_user_1"
},
]
},
{
"_id": {
"$oid": "63db1a68ef527b03093e78d4"
},
"user_id": "id_user_1",
"est_zone": {
"_id": {
"$oid": "63db1ad58c3dc65723ce0ac9"
},
"zone": {
"temp": "tempo2"
},
"user_id": "id_user_1"
},
"est_tax": [
{
"_id": {
"$oid": "63db1ad58c3dc65723ce0aca"
},
"tax": {
"fam": "fam2"
},
"user_id": "id_user_1"
}
]
}
]
on the output:
first document must have only tempo1 and fam1
second document mst have only tempo2 and fam2
i new in mongoDB and still thinking like SQL,
I am open to suggestions, i read there's no problem with duplicate data (mb in user, idk)
but, i need to keep separate "est_zone" and "est_tax"
Thx for yout time!

Related

Merge documents from 2 collections in MongoDB & preserve property of a field

I have two collections, 1. temporaryCollection, 2. permanentCollection, I would like to take data from temporaryCollection and update in permanentCollection. To see the expected result see updatedPermanentCollection below.
Fields that are taken from Temporary collection and updated in Permanent collection are:
emailAddresses
phoneNumbers
ContactName
ContactNumber
For your info, the fields that are changed in Temporary collection
contacts[0]['emailAddresses']
contacts[0]['ContactName']
contacts[0]["phoneNumbers"]
contacts[0]["ContactNumber"]
Field that are that should not be changed after updation in UpdatedPermanentCollection is
contacts._id
Note: contacts is an Array of objects, for simplicity I have shown just one object.
I am currently using the below query which updates the permanentCollection but also overrides the contacts._id field. I don't want the contacts._id field to be overridden.
Here is my MongoDB Query
db.temporaryCollection.aggregate([
{
$match: {
userID: ObjectId("61d1efea2c0fab00340f47c8"),
},
},
{
$merge: {
into: "permanentCollection",
on: "userID",
whenMatched: "merge",
whenNotMatched: "insert",
},
},
]);
1. temporaryCollection
{
"_id": { "$oid": "61d1f04266289f003452d705" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [
{ "id": "6884", "label": "email1", "email": "addedemail#gmail.com" }
],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292930"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d744" },
"ContactName": "Sample User 1 Name Changed",
"ContactNumber": "+918984292930",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
2. permanentCollection
{
"_id": { "$oid": "61d1f04266289f003452d701" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292929"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d722" },
"ContactName": "Sample User 1",
"ContactNumber": "+918984292929",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
3. updatedPermanentCollection (Expected result)
{
"_id": { "$oid": "61d1f04266289f003452d701" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [
{ "id": "6884", "label": "email1", "email": "addedemail#gmail.com" }
],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292930"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d722" },
"ContactName": "Sample User 1 Name Changed",
"ContactNumber": "+918984292930",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
Try with this aggregation query.
db.temporarCollection.aggreagate(
[
{
"$lookup": {
"from": "permanantCollection",
"let": {
"user_id": "$userID"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$$user_id", "$userID"
]
}
}
}
],
"as": "pcontacts"
}
}, {
"$unwind": {
"path": "$pcontacts",
"preserveNullAndEmptyArrays": true
}
}, {
"$project": {
"contacts": {
"$map": {
"input": "$contacts",
"as": "contact",
"in": {
"tcontact": "$$contact",
"pcontact": {
"$first": {
"$filter": {
"input": "$pcontacts.contacts",
"as": "pcontact",
"cond": {
"$eq": [
"$$pcontact.recordID", "$$contact.recordID"
]
}
}
}
}
}
}
},
"userNumber": 1,
"userID": 1,
"_id": 0
}
}, {
"$project": {
"contacts": {
"$map": {
"input": "$contacts",
"as": "contact",
"in": {
"emailAddresses": "$$contact.tcontact.emailAddresses",
"phoneNumbers": "$$contact.tcontact.phoneNumbers",
"ContactName": "$$contact.tcontact.ContactName",
"ContactNumber": "$$contact.tcontact.ContactNumber",
"recordID": {
"$let": {
"vars": {},
"in": {
"$cond": {
"if": "$$contact.pcontact.recordID",
"then": "$$contact.pcontact.recordID",
"else": "$$contact.tcontact.recordID"
}
}
}
},
"_id": {
"$let": {
"vars": {},
"in": {
"$cond": {
"if": "$$contact.pcontact._id",
"then": "$$contact.pcontact._id",
"else": "$$contact.tcontact._id"
}
}
}
}
}
}
},
"userNumber": 1,
"userID": 1
}
}, {
"$merge": {
"into": "pc",
"on": "userID",
"whenMatched": "replace",
"whenNotMatched": "insert"
}
}
])
It is not a fully optimized query but it works.
Try to add $unset to db query.
db.temporaryCollection.aggregate([
{
$unset: "_id"
},
{
$match: {
userID: ObjectId("61d1efea2c0fab00340f47c8"),
},
},
{
$merge: {
into: "permanentCollection",
on: "userID",
whenMatched: "merge",
whenNotMatched: "insert",
},
},
]);

MongoDb: How to use $unwind to unwind an array inside the object itself and not outside of it

I have an aggregate function that returns this:
{"video": {
"heart_users": [
{
"_id": "5f55465f19a7630017d6e3d5",
"profile": "5f55465f19a7630017d6e3d6"
},
{
"_id": "5f89fd90fa8ca500170bff13",
"profile": "5f89fd90fa8ca500170bff14"
},
{
"_id": "5f8bf4c0353ee400171ce239",
"profile": "5f8bf4c0353ee400171ce23a"
},
{
"_id": "5f9002602c45b50017b4abe2",
"profile": "5f9002602c45b50017b4abe3"
},
{
"_id": "5f95421d8b89f90017f9218b",
"profile": "5f95421d8b89f90017f9218c"
},
{
"_id": "5fda62586578d80017c9620f",
"profile": "5fda62586578d80017c96210"
},
{
"_id": "5ff310bcc1f74500178338d9",
"profile": "5ff310bdc1f74500178338da"
},
{
"_id": "5ff33cd00338aa0017d58f00",
"profile": "5ff33cd10338aa0017d58f01"
},
{
"_id": "60007322dfbcd30017d1a122",
"profile": "60007322dfbcd30017d1a123"
},
{
"_id": "6005994da1172516089d0446",
"profile": "6005994ea1172516089d0447"
},
{
"_id": "604e6637ff16e841a70751c1",
"profile": "604e6638ff16e8d0c30751c2"
}
]
}
}
I would like to use $unwind and $lookup to populate video.heart_users.profile AND keep the same object structure above. In other words, I want the end-result to be something like this (Just like a normal populate).
{"video": {
"heart_users": [
{
"_id": "5f55465f19a7630017d6e3d5",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5f89fd90fa8ca500170bff13",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5f8bf4c0353ee400171ce239",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5f9002602c45b50017b4abe2",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5f95421d8b89f90017f9218b",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5fda62586578d80017c9620f",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5ff310bcc1f74500178338d9",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "5ff33cd00338aa0017d58f00",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "60007322dfbcd30017d1a122",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "6005994da1172516089d0446",
"profile": {"profile_field":"profile_field_data"}
},
{
"_id": "604e6637ff16e841a70751c1",
"profile": {"profile_field":"profile_field_data"}
}
]
}
}
I have managed to achieve a close result by using $unwind externally:
/** This works but, it unwinds heart_users externally instead of inside the heart_users array */
{
$lookup: {
from: "users",
localField: "video.heart_users",
foreignField: "_id",
as: "video.heart_users",
},
},
{ $unwind: "$video.heart_users" },
{
$lookup: {
from: "profiles",
localField: "video.heart_users.profile",
foreignField: "_id",
as: "video.heart_users.profile",
},
}
Any idea how to achieve the result I want?

MongoDb Compass export db ref as embedded JSON

Is there a way to export a collection with all DBRef Objects embedded in a single JSON?
I tried to export the collection from compass, but it does not resolve the dbrefs to embedded json.
Example of the data structures:
Process:
{
"_id": {
"$oid": "5f44e89aa1f4c77447629a29"
},
"name": "test process",
"description": "A test configuration for a process",
"milestones": [{
"$ref": "milestone",
"$id": {
"$oid": "5f5753636b75033a49b7cc7b"
}
}, {
"$ref": "milestone",
"$id": {
"$oid": "5f5753636b75033a49b7cc82"
}
}]
}
Milestones:
[{
"_id": {
"$oid": "5f5753636b75033a49b7cc7b"
},
"name": "S1",
"order": 0,
"results": [
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc79"
}
},
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc7a"
}
}
]
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc82"
},
"name": "S2",
"order": 1,
"results": [
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc7d"
}
},
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc7e"
}
},
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc7f"
}
},
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc80"
}
},
{
"$ref": "resultDefinition",
"$id": {
"$oid": "5f5753636b75033a49b7cc81"
}
}
]
}]
Phases:
{
"_id": {
"$oid": "5f5753636b75033a49b7cc7c"
},
"name": "P1",
"activityStream": {
"$ref": "activityStream",
"$id": {
"$oid": "5f5755076b75033a49b7cc83"
}
}
}
ResultDefinitions:
[{
"_id": {
"$oid": "5f5753636b75033a49b7cc79"
},
"name": "userresult",
"resultType": "User"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc7a"
},
"name": "planDateResult",
"resultType": "PlanDate"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc7d"
},
"name": "fileResult",
"resultType": "File"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc7e"
},
"name": "dateResult",
"resultType": "Date"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc7f"
},
"name": "textresult",
"resultType": "Text"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc80"
},
"name": "booleanResult",
"resultType": "Boolean"
},{
"_id": {
"$oid": "5f5753636b75033a49b7cc81"
},
"name": "numberResult",
"resultType": "Number"
}]
Relations:
Process can have n milestones. Milestone has one or no Phase. Phase has more nested paths, but not relevant for an example. Milestone can have n ResultDefinitions
You can make a aggregation query and use $out operator, this will copy query result in separate collection, you can modify your query as per your requirement, see the last stage is $out: <collection name>, just provide the name of collection and execute this query, this will copy result in that collection, and you can export that collectoin.
db.process.aggregate([
{ $unwind: "$milestones" },
{
$lookup: {
from: "milestone",
let: { id: "$milestones.$id" },
pipeline: [
{ $match: { $expr: { $eq: ["$$id", "$_id"] } } },
{ $unwind: "$results" },
{
$lookup: {
from: "resultDefinition",
localField: "results.$id",
foreignField: "_id",
as: "results"
}
},
{ $unwind: "$results" },
{
$group: {
_id: "$_id",
name: { $first: "$name" },
order: { $first: "$order" },
results: { $push: "$results" }
}
}
],
as: "milestones"
}
},
{ $unwind: "$milestones" },
{
$group: {
_id: "$_id",
name: { $first: "$name" },
description: { $first: "$description" },
milestones: { $push: "$milestones" }
}
},
// you can specify the name of collection that you want
{ $out: "collection name" }
])
Playground
You can Also Export Mongo Collection in JSON Format by this command,
mongoexport -d <db-name> -c <collection-name> --out <collection-name>.json

mongodb aggregate lookup with a query

I have collections with following values:
reports
{
"_id": { "$oid": "5f05e1d13e0f6637739e215b" },
"testReport": [
{
"name": "Calcium",
"value": "87",
"slug": "ca",
"details": {
"description": "description....",
"recommendation": "recommendation....",
"isNormal": false
}
},
{
"name": "Magnesium",
"value": "-98",
"slug": "mg",
"details": {
"description": "description....",
"recommendation": "recommendation....",
"isNormal": false
}
}
],
"patientName": "Patient Name",
"clinicName": "Clinic",
"gender": "Male",
"bloodGroup": "A",
"createdAt": { "$date": "2020-07-08T15:10:09.612Z" },
"updatedAt": { "$date": "2020-07-08T15:10:09.612Z" }
},
setups
{
"_id": { "$oid": "5efcba7503f4693d164e651d" },
"code": "Ca",
"codeLower": "ca",
"name": "Calcium",
"valueFrom": -75,
"valueTo": -51,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7503f4693d164e651e" }, // <=== should find this for Calcium
"code": "Ca",
"codeLower": "ca",
"name": "Calcium",
"valueFrom": 76,
"valueTo": 100,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7603f4693d164e65bb" }, // <=== should find this for Magnesium
"code": "Mg",
"codeLower": "mg",
"name": "Magnesium",
"valueFrom": -100,
"valueTo": -76,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7503f4693d164e6550" },
"code": "Mg",
"codeLower": "mg",
"name": "Magnesium",
"valueFrom": 76,
"valueTo": 100,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
}
I want to search the value from reports collection and check whether the value is in range from the setups collection and return the _id and add the returned _ids in setupIds field on reports collection.
I tried with the following aggregation framework:
db.reports.aggegrate([
{
'$match': {
'_id': new ObjectId('5f05e1d13e0f6637739e215b')
}
}, {
'$lookup': {
'from': 'setups',
'let': {
'testValue': '$testReport.value',
'testName': '$testReport.name'
},
'pipeline': [
{
'$match': {
'$expr': {
{
'$and': [
{
'$eq': [
'$name', '$$testName'
]
}, {
'$gte': [
'$valueTo', '$$testValue'
]
}, {
'$lte': [
'$valueFrom', '$$testValue'
]
}
]
}
}
}
}
],
'as': 'setupIds'
}
}
])
This query didn't find the expected results.
This is the updated reports collection I want:
{
"_id": { "$oid": "5f05e1d13e0f6637739e215b" },
"setupIds": [{ "$oid": "5efcba7503f4693d164e651e" }, { "$oid": "5efcba7603f4693d164e65bb" }], // <=== Here, array of the ObjectId (ref: "Setups")
"patientName": "Patient Name",
"clinicName": "Clinic",
"gender": "Male",
"bloodGroup": "A",
"createdAt": { "$date": "2020-07-08T15:10:09.612Z" },
"updatedAt": { "$date": "2020-07-08T15:10:09.612Z" }
},
You can try like following
[{
$match: {
_id: ObjectId('5f05e1d13e0f6637739e215b')
}
}, {
$unwind: {
path: "$testReport"
}
}, {
$lookup: {
from: 'setup',
'let': {
testValue: {
$toInt: '$testReport.value'
},
testName: '$testReport.name'
},
pipeline: [{
$match: {
$expr: {
$and: [{
"$eq": [
"$name",
"$$testName"
]
},
{
"$gte": [
"$valueTo",
"$$testValue"
]
},
{
"$lte": [
"$valueFrom",
"$$testValue"
]
}
]
}
}
}],
as: 'setupIds'
}
}, {
$group: {
_id: "$_id",
patientName: {
$first: "$patientName"
},
clinicName: {
$first: "$clinicName"
},
gender: {
$first: "$gender"
},
bloodGroup: {
$first: "$bloodGroup"
},
createdAt: {
$first: "$createdAt"
},
updatedAt: {
$first: "$updatedAt"
},
setupIds: {
$addToSet: "$setupIds._id"
}
}
}, {
$addFields: {
setupIds: {
$reduce: {
input: "$setupIds",
initialValue: [],
in: {
$setUnion: ["$$this", "$$value"]
}
}
}
}
}]
Working Mongo playground

Filter nested array in mongodb? [duplicate]

This question already has answers here:
Find in Double Nested Array MongoDB
(2 answers)
Closed 4 years ago.
I have a document that looks like so:
{
"_id": {
"$oid": "5b1586ccf0c56353e89d330b"
},
"address": {
"street": "123 Street",
"address2": "Address 2",
"city": "Some City",
"state": "MI",
"zip": "12345"
},
"subs": [
{
"invoices": [
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AK",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fca54e6ee1d80c463612d"
},
"name": "1528810066348_RSA Logo.jpeg",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:27:46.931Z"
},
"size": 91819
}
],
"_id": {
"$oid": "5b1fca54e6ee1d80c463612c"
},
"desc": "2",
"amt": 2
}
],
"_id": {
"$oid": "5b1fca54e6ee1d80c463612b"
}
}
],
"_id": {
"$oid": "5b1fc7f23b595481d4599f58"
},
"email": "a#a.com",
"scope": "Roof",
},
{
"invoices": [
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AL",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fca2fe6ee1d80c463612a"
},
"name": "1528810029700_RSA Stamp.png",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:27:10.403Z"
},
"size": 238113
}
],
"_id": {
"$oid": "5b1fca2fe6ee1d80c4636129"
},
"desc": "1",
"amt": 1
}
],
"_id": {
"$oid": "5b1fca2fe6ee1d80c4636128"
}
},
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AL",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c40"
},
"name": "1528811607099_error page.PNG",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:53:28.080Z"
},
"size": 224772
}
],
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c3f"
},
"desc": "3",
"amt": 3
}
],
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c3e"
}
}
],
"_id": {
"$oid": "5b1fc7f23b595481d4599f55"
},
"email": "b#b.com",
"scope": "Siding",
}
],
"firstName": "",
"lastName": "",
}
My issue is that I want to be able to access a specific invoices of a specific subs.
I am new to Mongo/Mongoose so it is possible I am doing something completely wrong and I would be more than happy with any answer/criticism on how I am approaching this.
-- tweaked answer --
Job.aggregate([
{
$match: {
"_id": mongoose.Types.ObjectId(req.body.jobID)
}
},
{
$unwind: "$subs"
},
{
$match: {
"subs._id": mongoose.Types.ObjectId(req.body.subID)
}
},
{
$unwind: "$subs.invoices"
},
{
$match: {
"subs.invoices._id": mongoose.Types.ObjectId(req.body.invID)
}
},
{
$project: {
"_id": 1,
"subs.invoices": 1
}
}
], function(err, job) {
if (err) throw err;
res.send(job);
});
You can try below aggregation...
Here this is a long process of deconstructing an array using $unwind and rebuild the array using $group
db.collection.aggregate([
{ "$match": { "_id": "1111" } },
{ "$unwind": "$subs" },
{ "$match": { "subs._id": "2222" } },
{ "$unwind": "$subs.invoices" },
{ "$match": { "subs.invoices._id": "3333" } },
{ "$group": {
"_id": {
"_id": "$_id",
"subs": "$subs._id"
},
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"address": { "$first": "$address" },
"subs": {
"$first": {
"_id": "$subs._id",
"email": "$subs.email",
"venue": "$subs.venue",
"scope": "$subs.scope"
}
},
"invoices": { "$push": "$subs.invoices" }
}},
{ "$group": {
"_id": "$_id._id",
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"address": { "$first": "$address" },
"subs": {
"$push": {
"_id": "$subs._id",
"email": "$subs.email",
"venue": "$subs.venue",
"scope": "$subs.scope",
"invoices": "$invoices"
}
}
}}
])
Or you can do this with $filter aggregation as well
db.collection.aggregate([
{ "$match": { "_id": "5b1586ccf0c56353e89d330b" }},
{ "$unwind": "$subs" },
{ "$match": { "subs._id": "5b1fc7f23b595481d4599f58" }},
{ "$project": {
"address": 1, "firstName": 1, "lastName": 1,
"subs.type": "$subs._id",
"subs.status": "$subs.email",
"subs.code": "$subs.scope",
"subs.invoices": {
"$filter": {
"input": "$subs.invoices",
"as": "invoice",
"cond": {
"$eq": [
"$$invoice._id",
"5b1fca54e6ee1d80c463612b"
]
}
}
}
}},
{ "$group": {
"_id": "$_id",
"address": { "$first": "$address" },
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"subs": { "$push": "$subs" }
}}
])