$set not setting nested values - mongodb

I am trying to $set with findOneAndUpdate, but my nested values are not setting properly.
Here is a snippet of my SCHEMA:
...
courseMap: {
hasCourseMap: { type: Boolean, default: false },
parentMap: { type: Schema.Types.ObjectId, ref: "CourseMap" },
colleges: [
{
name: { type: String },
_id: { type: Schema.Types.ObjectId, ref: "College" }
}
],
title: { type: String },
ninth: {
hsCourses: [
{
courseName: { type: String, required: true },
courseNumber: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "HighSchoolCourse",
autopopulate: true
}
}
],
collegeCourses: [
{
name: {
type: String,
required: true
},
courseNumber: { type: String, required: true },
description: { type: String },
courseCode: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "CollegeCourse",
autopopulate: true
}
}
],
skills: []
},
tenth: {
hsCourses: [
{
courseName: { type: String, required: true },
courseNumber: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "HighSchoolCourse",
autopopulate: true
}
}
],
collegeCourses: [
{
name: {
type: String,
required: true
},
courseNumber: { type: String, required: true },
description: { type: String },
courseCode: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "CollegeCourse",
autopopulate: true
}
}
],
skills: []
},
eleventh: {
hsCourses: [
{
courseName: { type: String, required: true },
courseNumber: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "HighSchoolCourse",
autopopulate: true
}
}
],
collegeCourses: [
{
name: {
type: String,
required: true
},
courseNumber: { type: String, required: true },
description: { type: String },
courseCode: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "CollegeCourse",
autopopulate: true
}
}
],
skills: []
},
twelfth: {
hsCourses: [
{
courseName: { type: String, required: true },
courseNumber: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "HighSchoolCourse",
autopopulate: true
}
}
],
collegeCourses: [
{
name: {
type: String,
required: true
},
courseNumber: { type: String, required: true },
description: { type: String },
courseCode: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "CollegeCourse",
autopopulate: true
}
}
],
skills: []
},
year5: {
hsCourses: [
{
courseName: { type: String, required: true },
courseNumber: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "HighSchoolCourse",
autopopulate: true
}
}
],
collegeCourses: [
{
name: {
type: String,
required: true
},
courseNumber: { type: String, required: true },
description: { type: String },
courseCode: { type: String, required: true },
_id: {
type: Schema.Types.ObjectId,
ref: "CollegeCourse",
autopopulate: true
}
}
],
skills: []
}
}
...
Here is my update object:
{
"$set": {
"courseMap": {
"hasCourseMap": true,
"parentMap": "5e07fb5b40b723f03935cb31",
"colleges": [
{
"_id": "5dfee8128eacd562f0338678",
"name": "Eastfield"
},
{
"_id": "5e06a566559c3013687cc0f1",
"name": "University of North Texas at Dallas"
}
],
"ninth": {
"hsCourses": [
{
"_id": "5dfee4bb008dfb2fa4e89a43",
"abbr": "MATH",
"courseNumber": "7897987",
"courseName": "GEOMETRY",
"timestamp": "2019-12-22T03:36:27.026Z",
"__v": 0
}
],
"collegeCourses": [
{
"_id": "5dfef4d75581475988759efc",
"HSEquivCourses": [
"5dfee4bb008dfb2fa4e89a43"
],
"college": "5dfee8128eacd562f0338678",
"name": "test1",
"courseNumber": "test",
"description": "tesst",
"__v": 0
}
]
},
"tenth": {
"hsCourses": [
{
"_id": "5dfee4bb008dfb2fa4e89a43",
"abbr": "MATH",
"courseNumber": "7897987",
"courseName": "GEOMETRY",
"timestamp": "2019-12-22T03:36:27.026Z",
"__v": 0
}
],
"collegeCourses": [
{
"_id": "5e07dceb63b72fe4b74473e2",
"college": "5e06a566559c3013687cc0f1",
"name": "TEST",
"courseNumber": "tesat",
"description": "",
"courseCode": "test",
"__v": 0
}
]
},
"eleventh": {
"hsCourses": [
{
"_id": "5dfee4bb008dfb2fa4e89a43",
"abbr": "MATH",
"courseNumber": "7897987",
"courseName": "GEOMETRY",
"timestamp": "2019-12-22T03:36:27.026Z",
"__v": 0
}
],
"collegeCourses": [
{
"_id": "5dfef06ebe4ae31e7c6344bb",
"HSEquivCourses": [
"5dfee4bb008dfb2fa4e89a43"
],
"college": "5dfee8128eacd562f0338678",
"name": "Psychology",
"courseNumber": "1301",
"description": "test",
"__v": 0
}
]
},
"twelfth": {
"hsCourses": [
{
"_id": "5dfee4bb008dfb2fa4e89a43",
"abbr": "MATH",
"courseNumber": "7897987",
"courseName": "GEOMETRY",
"timestamp": "2019-12-22T03:36:27.026Z",
"__v": 0
}
],
"collegeCourses": [
{
"_id": "5e07dceb63b72fe4b74473e2",
"college": "5e06a566559c3013687cc0f1",
"name": "TEST",
"courseNumber": "tesat",
"description": "",
"courseCode": "test",
"__v": 0
}
]
},
"year5": {
"hsCourses": [
{
"_id": "5dfee4bb008dfb2fa4e89a43",
"abbr": "MATH",
"courseNumber": "7897987",
"courseName": "GEOMETRY",
"timestamp": "2019-12-22T03:36:27.026Z",
"__v": 0
}
],
"collegeCourses": [
{
"_id": "5dfef06ebe4ae31e7c6344bb",
"HSEquivCourses": [
"5dfee4bb008dfb2fa4e89a43"
],
"college": "5dfee8128eacd562f0338678",
"name": "Psychology",
"courseNumber": "1301",
"description": "test",
"__v": 0
}
]
}
}
}
}
And after using StudentProfile.findOneAndUpdate({ _id: user.profile }, update)
The following is updated, which is the top level key values, but my nested values are not setting.
"courseMap":{
"hasCourseMap" : true,
"parentMap" : ObjectId("5e07fb5b40b723f03935cb31"),
"colleges" : [
{
"_id" : ObjectId("5dfee8128eacd562f0338678"),
"name" : "Eastfield"
},
{
"_id" : ObjectId("5e06a566559c3013687cc0f1"),
"name" : "University of North Texas at Dallas"
}
],
"ninth" : {
"hsCourses" : [
{
}
],
"collegeCourses" : [
{
}
]
},
"tenth" : {
"hsCourses" : [
{
}
],
"collegeCourses" : [
{
}
]
},
"eleventh" : {
"hsCourses" : [
{
}
],
"collegeCourses" : [
{
}
]
},
"twelfth" : {
"hsCourses" : [
{
}
],
"collegeCourses" : [
{
}
]
},
"year5" : {
"hsCourses" : [
{
}
],
"collegeCourses" : [
{
}
]
}
}
Here is a snippet of the document before the update occurs:
...
"courseMap" : {
"hasCourseMap" : false,
}
...

You are assuming you want to put everything in $set, which is incorrect.
You can breakdown your update statement.
Consider following example, I start with document:
{
a: 1,
c: [
"1",
"2"
],
d: [
{
d1: "3",
d2: "4"
},
{
d3: "5"
}
],
e: {
e1: [
"6",
"7"
]
},
f: [
]
}
And when I run:
db.inserter.updateOne({
},
{
$set: {
c: [
"3.3"
]
},
$push: {
f: {
d4: "5.5"
}
}
})
Outcome:
{
"_id": ObjectId("5e1de4b6afa8c2dd9dcfd79c"),
"a": 1,
"c": [
"3.3"
],
"d": [
{
"d1": "3",
"d2": "4"
},
{
"d3": "5"
}
],
"e": {
"e1": [
"6",
"7"
]
},
"f": [
{
"d4": "5.5"
}
]
}
the trick?
The update document has two parts (could be more, and you could do dot notation) $set and $push
{ $set: { c: ["3.3"] }, $push: { f: { d4: "5.5" } } }
Running your query as it is, it works with the following output:
{
"_id" : ObjectId("5e1de61dafa8c2dd9dcfd79d"),
"courseMap" : {
"hasCourseMap" : true,
"parentMap" : "5e07fb5b40b723f03935cb31",
"colleges" : [
{
"_id" : "5dfee8128eacd562f0338678",
"name" : "Eastfield"
},
{
"_id" : "5e06a566559c3013687cc0f1",
"name" : "University of North Texas at Dallas"
}
],
"ninth" : {
"hsCourses" : [
{
"_id" : "5dfee4bb008dfb2fa4e89a43",
"abbr" : "MATH",
"courseNumber" : "7897987",
"courseName" : "GEOMETRY",
"timestamp" : "2019-12-22T03:36:27.026Z",
"__v" : 0
}
],
"collegeCourses" : [
{
"_id" : "5dfef4d75581475988759efc",
"HSEquivCourses" : [
"5dfee4bb008dfb2fa4e89a43"
],
"college" : "5dfee8128eacd562f0338678",
"name" : "test1",
"courseNumber" : "test",
"description" : "tesst",
"__v" : 0
}
]
},
"tenth" : {
"hsCourses" : [
{
"_id" : "5dfee4bb008dfb2fa4e89a43",
"abbr" : "MATH",
"courseNumber" : "7897987",
"courseName" : "GEOMETRY",
"timestamp" : "2019-12-22T03:36:27.026Z",
"__v" : 0
}
],
"collegeCourses" : [
{
"_id" : "5e07dceb63b72fe4b74473e2",
"college" : "5e06a566559c3013687cc0f1",
"name" : "TEST",
"courseNumber" : "tesat",
"description" : "",
"courseCode" : "test",
"__v" : 0
}
]
},
"eleventh" : {
"hsCourses" : [
{
"_id" : "5dfee4bb008dfb2fa4e89a43",
"abbr" : "MATH",
"courseNumber" : "7897987",
"courseName" : "GEOMETRY",
"timestamp" : "2019-12-22T03:36:27.026Z",
"__v" : 0
}
],
"collegeCourses" : [
{
"_id" : "5dfef06ebe4ae31e7c6344bb",
"HSEquivCourses" : [
"5dfee4bb008dfb2fa4e89a43"
],
"college" : "5dfee8128eacd562f0338678",
"name" : "Psychology",
"courseNumber" : "1301",
"description" : "test",
"__v" : 0
}
]
},
"twelfth" : {
"hsCourses" : [
{
"_id" : "5dfee4bb008dfb2fa4e89a43",
"abbr" : "MATH",
"courseNumber" : "7897987",
"courseName" : "GEOMETRY",
"timestamp" : "2019-12-22T03:36:27.026Z",
"__v" : 0
}
],
"collegeCourses" : [
{
"_id" : "5e07dceb63b72fe4b74473e2",
"college" : "5e06a566559c3013687cc0f1",
"name" : "TEST",
"courseNumber" : "tesat",
"description" : "",
"courseCode" : "test",
"__v" : 0
}
]
},
"year5" : {
"hsCourses" : [
{
"_id" : "5dfee4bb008dfb2fa4e89a43",
"abbr" : "MATH",
"courseNumber" : "7897987",
"courseName" : "GEOMETRY",
"timestamp" : "2019-12-22T03:36:27.026Z",
"__v" : 0
}
],
"collegeCourses" : [
{
"_id" : "5dfef06ebe4ae31e7c6344bb",
"HSEquivCourses" : [
"5dfee4bb008dfb2fa4e89a43"
],
"college" : "5dfee8128eacd562f0338678",
"name" : "Psychology",
"courseNumber" : "1301",
"description" : "test",
"__v" : 0
}
]
}
}
}

The fields I was using to $set for the ninth, tenth, etc came from a mongoose document and I was directly attempting to save them. I used .lean() and my query worked.

Related

Mongo aggregation failing with "Exceeded memory limit for $group"

We have a query which gets the min and max latitude/longitude. We use aggregation query for this. We have 2 million documents.
We are getting the below error while running aggregation query. How can we fix this? Will the performance degrade if we use allowDiskUse:true? Or can we add some index which can fix this issue?
2021-04-02T23:57:16.682+0000 I COMMAND [conn2829719] command loc-service.locations command: aggregate { aggregate: "locations", pipeline: [ { $match: { customerId: "8047380094" } }, { $unwind: "$outdoorLocationInfo.location.coordinates" }, { $group: { _id: "$_id", longitude: { $first: "$outdoorLocationInfo.location.coordinates" }, latitude: { $last: "$outdoorLocationInfo.location.coordinates" } } }, { $group: { _id: null, minLongitude: { $min: "$longitude" }, maxLongitude: { $max: "$longitude" }, minLatitude: { $min: "$latitude" }, maxLatitude: { $max: "$latitude" } } } ], cursor: {}, allowDiskUse: false, $db: "loc-service", $clusterTime: { clusterTime: Timestamp(1617407827, 2), signature: { hash: BinData(0, F980F28628AF21C214BD2D3F4B7C48F56ACB47BD), keyId: 6914764447386959875 } }, lsid: { id: UUID("a6e20fee-7714-4460-bdc8-2019425c7ff0") } } planSummary: IXSCAN { customerId: 1, deviceId: 1 } numYields:7900 ok:0 errMsg:"Exceeded memory limit for $group, but didn't allow external sort. Pass allowDiskUse:true to opt in." errName:Location16945 errCode:16945 reslen:313 locks:{ Global: { acquireCount: { r: 8061 } }, Database: { acquireCount: { r: 8060 } }, Collection: { acquireCount: { r: 8060 } } } storage:{} protocol:op_msg 5448ms
The query
db.locations.aggregate([
{
$match: {
customerId: "8047380094"
}
},
{
$unwind: "$outdoorLocationInfo.location.coordinates"
},
{
$group: {
_id: "$_id",
longitude: {
$first: "$outdoorLocationInfo.location.coordinates"
},
latitude: {
$last: "$outdoorLocationInfo.location.coordinates"
}
}
},
{
$group: {
_id: null,
minLongitude: {
$min: "$longitude"
},
maxLongitude: {
$max: "$longitude"
},
minLatitude: {
$min: "$latitude"
},
maxLatitude: {
$max: "$latitude"
}
}
}
])
Indexes we have on this collection:
db.locations.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "loc-service.locations"
},
{
"v" : 2,
"key" : {
"customerId" : 1,
"deviceId" : 1
},
"name" : "customerId_1_deviceId_1",
"ns" : "loc-service.locations",
"sparse" : true,
"background" : true
},
{
"v" : 2,
"key" : {
"customerId" : 1,
"geoHash" : 1
},
"name" : "customerId_1_geoHash_1",
"ns" : "loc-service.locations",
"sparse" : true,
"background" : true
},
{
"v" : 2,
"key" : {
"customerId" : 1,
"outdoorLocationInfo.location" : "2dsphere"
},
"name" : "customerId_1_outdoorLocationInfo.location_2dsphere",
"ns" : "loc-service.locations",
"sparse" : true,
"background" : true,
"2dsphereIndexVersion" : 3
},
{
"v" : 2,
"key" : {
"customerId" : 1,
"outdoorLocationInfo.location.coordinates" : 1
},
"name" : "customerId_1_outdoorLocationInfo.location.coordinates_1",
"ns" : "loc-service.locations",
"sparse" : true,
"background" : true
}
]
Sample Data:
db.locations.findOne()
{
"_id" : ObjectId("60551b70a48edf83848607d2"),
"outdoorLocationInfo" : {
"location" : {
"type" : "Point",
"coordinates" : [
-95.330024,
36.262476
]
}
},
"customerId" : "2868306879",
"deviceId" : "6eN7sMEOP1e",
"geoHash" : "9yknq9qu1rqp",
}
Thanks
I think you can simplify your query with $arrayElemAt
db.collection.aggregate([
{
$match: {
customerId: "8047380094"
}
},
{
$group: {
_id: null,
"maxLatitude": {
"$max": {
"$arrayElemAt": [
"$outdoorLocationInfo.location.coordinates",
1
]
}
},
"maxLongitude": {
"$max": {
"$arrayElemAt": [
"$outdoorLocationInfo.location.coordinates",
0
]
}
},
"minLatitude": {
"$min": {
"$arrayElemAt": [
"$outdoorLocationInfo.location.coordinates",
1
]
}
},
"minLongitude": {
"$min": {
"$arrayElemAt": [
"$outdoorLocationInfo.location.coordinates",
0
]
}
},
}
}
])
Try it here

Mongodb $unwind removes objects. if $lookup doesn't have reference [duplicate]

This question already has an answer here:
Handling unwind for the non existing embedded document [duplicate]
(1 answer)
Closed 3 years ago.
If country doesn't have reference states and cities. $unwind removes country name from the collections.
Expected Output will be Mongodb should return country name even if the country doesn't any states and cities reference.
Country Collection:
[
{
"_id": "5d052c76df076d23a48d4a3b",
"name": "India"
},
{
"_id": "5d052c76df076d23a48d4b07",
"name": "Indonesia"
},
{
"_id": "5d052c76df076d23a48d22f4",
"name": "Iran"
}
]
State Collection:
[
{
"_id": "5d2236c37ed1112b3cc41397",
"name": "Andaman and Nicobar Islands",
"countryId": "5d052c76df076d23a48d4a3b"
},
{
"_id": "5d2236c37ed1112b3cc41398",
"name": "Andhra Pradesh",
"countryId": "5d052c76df076d23a48d4a3b"
}
]
City Collection:
[
{
"name": "Port Blair",
"stateId": "5d2236c37ed1112b3cc41397"
},
{
"name": "Adoni",
"stateId": "5d2236c37ed1112b3cc41398"
}
]
Query:
Country.aggregate([
{
$lookup:{
from: 'states',
localField:'_id',
foreignField:'countryId',
as:'states'
}
},
{
$unwind: {
path: "$states"
}
},
{
$lookup:{
from: 'cities',
localField:'states._id',
foreignField:'stateId',
as:'states.cities'
}
},
{
$group: {
_id: {
_id: '$_id',
name: '$name'
},
states: {
$push: '$states'
}
}
},
{
$project: {
_id: '$_id._id',
name: '$_id.name',
states: 1
}
}
])
Output:
[
{
"_id":"5d052c76df076d23a48d4a3b",
"name":"India",
"states":[
{
"_id":"5d2236c37ed1112b3cc41397",
"name":"Andaman and Nicobar Islands",
"countryId":"5d052c76df076d23a48d4a3b",
"cities":[
{
"name":"Port Blair",
"stateId":"5d2236c37ed1112b3cc41397"
}
]
},
{
"_id":"5d2236c37ed1112b3cc41398",
"name":"Andhra Pradesh",
"countryId":"5d052c76df076d23a48d4a3b",
"cities":[
{
"name":"Adoni",
"stateId":"5d2236c37ed1112b3cc41398"
}
]
}
]
}
]
Expected Output:
[
{
"_id":"5d052c76df076d23a48d4a3b",
"name":"India",
"states":[
{
"_id":"5d2236c37ed1112b3cc41397",
"name":"Andaman and Nicobar Islands",
"countryId":"5d052c76df076d23a48d4a3b",
"cities":[
{
"name":"Port Blair",
"stateId":"5d2236c37ed1112b3cc41397"
}
]
},
{
"_id":"5d2236c37ed1112b3cc41398",
"name":"Andhra Pradesh",
"countryId":"5d052c76df076d23a48d4a3b",
"cities":[
{
"name":"Adoni",
"stateId":"5d2236c37ed1112b3cc41398"
}
]
}
]
},
{
"_id":"5d052c76df076d23a48d4b07",
"name":"Indonesia",
"states":[
]
},
{
"_id":"5d052c76df076d23a48d22f4",
"name":"Iran",
"states":[
]
}
]
just add " preserveNullAndEmptyArrays: true " to $unwind
Country.aggregate([
{
$lookup:{
from: 'states',
localField:'_id',
foreignField:'countryId',
as:'states'
}
},
{
$unwind: {
path: "$states",
preserveNullAndEmptyArrays: true
}
},
{
$lookup:{
from: 'cities',
localField:'states._id',
foreignField:'stateId',
as:'states.cities'
}
},
{
$group: {
_id: {
_id: '$_id',
name: '$name'
},
states: {
$push: '$states'
}
}
},
{
$project: {
_id: '$_id._id',
name: '$_id.name',
states: 1
}
}
])
output
[
{
"states" : [
{
"cities" : []
}
],
"_id" : "5d052c76df076d23a48d22f4",
"name" : "Iran"
},
{
"states" : [
{
"cities" : []
}
],
"_id" : "5d052c76df076d23a48d4b07",
"name" : "Indonesia"
},
{
"states" : [
{
"_id" : "5d2236c37ed1112b3cc41397",
"name" : "Andaman and Nicobar Islands",
"countryId" : "5d052c76df076d23a48d4a3b",
"cities" : [
{
"_id" : ObjectId("5d38ccb6f9c5fa48bf099027"),
"name" : "Port Blair",
"stateId" : "5d2236c37ed1112b3cc41397"
}
]
},
{
"_id" : "5d2236c37ed1112b3cc41398",
"name" : "Andhra Pradesh",
"countryId" : "5d052c76df076d23a48d4a3b",
"cities" : [
{
"_id" : ObjectId("5d38ccbcf9c5fa48bf09902a"),
"name" : "Adoni",
"stateId" : "5d2236c37ed1112b3cc41398"
}
]
}
],
"_id" : "5d052c76df076d23a48d4a3b",
"name" : "India"
}
]

can't sort in mongo/mongoose with populate

I can't seem to sort this mongo/mongoose query. The first one returns the exact results, just not sorted in the opposite direction.
const UserSchema = new Schema({
username : String,
current : { type: Schema.Types.ObjectId, ref: 'News' },
friends : [{ user: { type: Schema.Types.ObjectId, ref: 'User'}, status: String }],
profile : {...}
})
const NewsSchema = new Schema({
user : { type: Schema.Types.ObjectId, ref: 'User' },
owner : { type: Schema.Types.ObjectId, ref: 'User' },
date : Date,
desc : String
});
const News = mongoose.model('News', NewsSchema);
const User = mongoose.model('User', UserSchema);
I've tried
.populate({
path: 'friends.user',
model: 'User',
select: 'profile.firstname profile.lastname profile.avatar username current -_id',
populate: {
path: 'current',
model: 'News',
select: 'date owner desc',
populate: {
path: 'owner',
model: 'User',
select: 'profile.firstname profile.lastname profile.avatar username'
},
},
})
.sort({'current.date': -1})
as well as
.populate({
path: 'friends.user',
model: 'User',
select: 'profile.firstname profile.lastname profile.avatar username current -_id',
populate: {
path: 'current',
model: 'News',
select: 'date owner desc',
options: { sort: { date: -1 } }
},
})
and this one which gives an error
User.findOne({ _id: req.userId }, 'friends -_id')
.populate({
path: 'friends.user',
model: 'User',
select: 'profile.firstname profile.lastname profile.avatar username current -_id',
populate: {
path: 'current',
model: 'News',
select: 'date owner desc',
},
options: {
sort: { date: -1 }
}
})
{
"message": "MongooseError: Cannot populate with `sort` on path friends.user because it is a subproperty of a document array"
}
with the first and second one, it comes back as
{
"friends": [
{
"_id": "5b51fd7c3f4ec33546a0664f",
"user": {
"profile": {
...
},
"current": {
"date": "2018-07-20T15:19:00.968Z"
}
}
},
{
"_id": "5b51fdb53f4ec33546a06655",
"user": {
"profile": {
...
},
"current": {
"date": "2018-07-20T15:19:45.102Z"
}
}
}
]
}
It should be reversed as "date": "2018-07-20T15:19:45.102Z" is more recent.
Is there a better more efficient way of doing the same thing with aggregate and lookup?
Users collection
{
"_id" : ObjectId("5b51fd2a3f4ec33546a06648"),
"profile" : {
"firstname" : "user1",
"lastname" : "user1"
"avatar" : "user1.png"
}
"username" : "user1",
"friends" : [
{
"_id" : ObjectId("5b51fd7c3f4ec33546a0664f"),
"user" : ObjectId("5b51fd643f4ec33546a0664c")
},
{
"_id" : ObjectId("5b51fdb53f4ec33546a06655"),
"user" : ObjectId("5b51fd903f4ec33546a06652")
}
],
"__v" : 5,
"current" : ObjectId("5b51fd2a3f4ec33546a06649")
},
{
"_id" : ObjectId("5b51fd643f4ec33546a0664c"),
"profile" : {
"firstname" : "user2",
"lastname" : "user2"
"avatar" : "user2.png"
}
"friends" : [
{
"_id" : ObjectId("5b51fdcd3f4ec33546a06658"),
"user" : ObjectId("5b51fd2a3f4ec33546a06648")
}
],
"__v" : 5,
"current" : ObjectId("5b51fd643f4ec33546a0664d"),
"username" : "user2"
},
{
"_id" : ObjectId("5b51fd903f4ec33546a06652"),
"profile" : {
"firstname" : "user3",
"lastname" : "user3"
"avatar" : "user3.png"
},
"friends" : [
{
"_id" : ObjectId("5b51fdce3f4ec33546a0665a"),
"user" : ObjectId("5b51fd2a3f4ec33546a06648")
}
],
"__v" : 5,
"current" : ObjectId("5b51fd903f4ec33546a06653"),
"username" : "user3"
}
New collection
{
"_id" : ObjectId("5b51fd2a3f4ec33546a06649"),
"user" : ObjectId("5b51fd2a3f4ec33546a06648"),
"owner" : ObjectId("5b51fd2a3f4ec33546a06648"),
"date" : ISODate("2018-07-20T15:18:02.962Z"),
"desc" : "user1 gibberish",
"__v" : 0
}
{
"_id" : ObjectId("5b51fd643f4ec33546a0664d"),
"user" : ObjectId("5b51fd643f4ec33546a0664c"),
"owner" : ObjectId("5b51fd643f4ec33546a0664c"),
"date" : ISODate("2018-07-20T15:19:00.968Z"),
"desc" : "user2 gibberish",
"__v" : 0
}
{
"_id" : ObjectId("5b51fd903f4ec33546a06653"),
"user" : ObjectId("5b51fd903f4ec33546a06652"),
"owner" : ObjectId("5b51fd903f4ec33546a06652"),
"date" : ISODate("2018-07-20T15:19:44.102Z"),
"desc" : "user3 gibberish",
"__v" : 0
}
You can try below aggregation
User.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(req.userId) } },
{ "$unwind": "$friends" },
{ "$lookup": {
"from": User.collection.name,
"let": { "friendId": "$friends.user" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$friendId" ] } } },
{ "$lookup": {
"from": News.collection.name,
"let": { "current": "$current" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$_id", "$$current" ] } } },
],
"as": "current"
}},
{ "$unwind": "$current" }
],
"as": "friends.user"
}},
{ "$unwind": "$friends.user" },
{ "$sort": { "friends.user.current.date": 1 }},
{ "$group": {
"_id": "$_id",
"username": { "$first": "$username" },
"profile": { "$first": "$profile" },
"friends": { "$push": "$friends" }
}}
])

Select subdocument of a document and exclude a property of if in mongoDB

I have the following document structure in mongoDb.
I want to be able to select only all the courses, without the teacherproperty in it. How can I do that?
I have tried the following but it doesn´t work. I would also like that when it finds the result it returns that to the console?
How can I do that?
student.findCourses = (fcallback) => {
var jCourses = {
"courses": [
{
"courseName": "Web-development"
},
{
"courseName": "Databases"
},
{
"courseName": "Databases"
}
]
}
global.db.collection('students').find(({}, { jCourses: true, _id: false, firstName: false, lastName: false, age: false, teachers: false }).toArray, (err) => {
if (err) {
var jError = { "status": "error", "message": "ERROR -> student.js -> 001" }
console.log(jError)
return fcallback(true, jError)
}
var jOk = { "status": "ok", "message": "student.js -> found -> 000" }
console.log(jOk)
return fcallback(false, jOk)
})
}
The document:
{
"firstName": "Sarah",
"lastName": "Jepsen",
"age": 27,
"courses": [
{
"courseName": "Web-development",
"teachers": [
{
"firstName": "Santiago",
"lastName": "Donoso"
}
]
},
{
"courseName": "Databases",
"teachers": [
{
"firstName": "Dany",
"lastName": "Kallas"
},
{
"firstName": "Rune",
"lastName": "Lyng"
}
]
},
{
"courseName": "Interface-Design",
"teachers": [
{
"firstName": "Roxana",
"lastName": "Stolniceanu"
}
]
}
]
}
The result should look like this:
{
"courses": [
{
"courseName": "Web-development"
},
{
"courseName": "Databases"
},
{
"courseName": "Databases"
}
]
}
You can use dot syntax.
Like this :
global.db.collection('students').find({}, { "courses.courseName": true, _id: false }).toArray((err, docs) => {
if (err) {
var jError = { "status": "error", "message": "ERROR -> student.js -> 001" }
console.log(jError)
return fcallback(true, jError)
}
var jOk = { "status": "ok", "message": "student.js -> found -> 000" }
console.log(jOk);
console.log(docs); // Will print to the console the data that you want
return fcallback(false, jOk)
})
It will print only the courseName of courses.
Example on mongo shell :
> db.users.find().pretty()
{
"_id" : ObjectId("59ff442eb40a672f2223a14f"),
"firstName" : "Sarah",
"lastName" : "Jepsen",
"age" : 27,
"courses" : [
{
"courseName" : "Web-development",
"teachers" : [
{
"firstName" : "Santiago",
"lastName" : "Donoso"
}
]
},
{
"courseName" : "Databases",
"teachers" : [
{
"firstName" : "Dany",
"lastName" : "Kallas"
},
{
"firstName" : "Rune",
"lastName" : "Lyng"
}
]
},
{
"courseName" : "Interface-Design",
"teachers" : [
{
"firstName" : "Roxana",
"lastName" : "Stolniceanu"
}
]
}
]
}
> db.users.find({}, {_id: 1, "courses.courseName": 1}).pretty()
{
"_id" : ObjectId("59ff442eb40a672f2223a14f"),
"courses" : [
{
"courseName" : "Web-development"
},
{
"courseName" : "Databases"
},
{
"courseName" : "Interface-Design"
}
]
}
> db.users.find({}, {_id: 0, "courses.courseName": 1}).pretty()
{
"courses" : [
{
"courseName" : "Web-development"
},
{
"courseName" : "Databases"
},
{
"courseName" : "Interface-Design"
}
]
}

Combine/Cross Product of nested elements MongoDB

Is there a way to combine / produce a cross product of nested elements within MongoDB.
As an example I have
{
images:
[
{
name: 'A',
url: 'urlA'
},
{
name: 'B',
url: 'urlB'
}
],
tags: [
{
name: 'Tag1',
description: 'description1'
},
{
name: 'Tag2',
description: 'description2'
}
]
}
By preferred result should be
[
{
url: 'urlA',
name: 'Tag1'
},
{
url: 'urlA',
name: 'Tag2'
},
{
url: 'urlB',
name: 'Tag1'
},
{
url: 'urlB',
name: 'Tag2'
}
]
Is it possible to store the generated documents in a new collection?
MongoDB Query
db.test.aggregate([
{ $unwind: '$images' },
{ $unwind: '$tags' },
{ "$group" :
{ "_id" :
{ "url": "$images.url", "name": "$tags.name" },
}
},
{ "$group" :
{ "_id" : null,
"result":
{ "$addToSet" :
{ "url" : "$_id.url", "name" : "$_id.name" }
},
}
},
{"$project": { "_id":0, "result": 1 }}
]);
Output
{
"result": [
{
"url": "urlA",
"name": "Tag1"
},
{
"url": "urlA",
"name": "Tag2"
},
{
"url": "urlB",
"name": "Tag1"
},
{
"url": "urlB",
"name": "Tag2"
}
]}