Mongoose: Push or replace element into array - node.js

I'm using Mongoose (MongoDB in node.js), and after reading this answer:
Replace value in array
I have another question:
Is it possible to do in the same sentence: push element into array or replace if this element is existing in the array?
Maybe something like this? (The example doesn't work)
Model.findByIdAndUpdate(id,
{
$pull: {"readers": {user: req.user.id}},
$push:{"readers":{user: req.user.id, someData: data}}
},{multi:true},callback)
Message error:
errmsg: 'exception: Cannot update \'readers\' and \'readers\' at the same time
Reference:
https://stackoverflow.com/a/15975515/4467741
Thank you!

Multiple operations on the same property path are simply not allowed in a single request, with the main reason being that the operations themselves have "no particular order" in the way the engine assigns them as the document is updated, and therefore there is a conflict that should be reported as an error.
So the basic abstraction on this is that you have "two" update operations to perform, being one to "replace" the element where it exists, and the other to "push" the new element where it does not exist.
The best way to implement this is using "Bulk" operations, which whilst still "technically" is "two" update operations, it is however just a "single" request and response, no matter which condition was met:
var bulk = Model.collection.initializeOrderedBulkOp();
bulk.find({ "_id": id, "readers.user": req.user.id }).updateOne({
"$set": { "readers.$.someData": data } }
});
bulk.find({ "_id": id, "readers.user": { "$ne": req.user.id } }).updateOne({
"$push": { "readers": { "user": req.user.id, "someData": data } }
});
bulk.execute(function(err,result) {
// deal with result here
});
If you really "need" the updated object in result, then this truly becomes a "possible" multiple request following the logic where the array element was not found:
Model.findOneAndUpdate(
{ "_id": id, "readers.user": req.user.id },
{ "$set": { "readers.$.someData": data } },
{ "new": true },
function(err,doc) {
if (err) // handle error;
if (!doc) {
Model.findOneAndUpdate(
{ "_id": id, "readers.user": { "$ne": req.user.id } },
{ "$push": { "readers":{ "user": req.user.id, "someData": data } } },
{ "new": true },
function(err,doc) {
// or return here when the first did not match
}
);
} else {
// was updated on first try, respond
}
}
);
And again using you preferred method of not nesting callbacks with either something like async or nested promise results of some description, to avoid the basic indent creep that is inherrent to one action being dependant on the result of another.
Basically probably a lot more efficient to perform the updates in "Bulk" and then "fetch" the data afterwards if you really need it.
Complete Listing
var async = require('async'),
mongoose = require('mongoose')
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var userSchema = new Schema({
name: String
});
var dataSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
someData: String
},{ "_id": false });
var testSchema = new Schema({
name: String,
readers: [dataSchema]
});
var User = mongoose.model( 'User', userSchema ),
Test = mongoose.model( 'Test', testSchema );
var userId = null,
id = null;
async.series(
[
// Clean models
function(callback) {
async.each([User,Test],function(model,callback) {
model.remove({},callback);
},callback);
},
// Create a user
function(callback) {
User.create({ name: 'bill' },function(err,user) {
userId = user._id;
callback(err);
});
},
function(callback) {
Test.create({ name: 'Topic' },function(err,topic) {
id = topic._id;
console.log("initial state:");
console.log(topic);
callback(err);
});
},
// 1st insert array 2nd update match 1 modified
function(callback) {
var bulk = Test.collection.initializeOrderedBulkOp();
bulk.find({ "_id": id, "readers.user": userId }).updateOne({
"$set": { "readers.$.someData": 1 }
});
bulk.find({ "_id": id, "readers.user": { "$ne": userId }}).updateOne({
"$push": { "readers": { "user": userId, "someData": 1 } }
});
bulk.execute(function(err,result) {
if (err) callback(err);
console.log("update 1:");
console.log(JSON.stringify( result, undefined, 2));
Test.findById(id,function(err,doc) {
console.log(doc);
callback(err);
});
});
},
// 2nd replace array 1st update match 1 modified
function(callback) {
var bulk = Test.collection.initializeOrderedBulkOp();
bulk.find({ "_id": id, "readers.user": userId }).updateOne({
"$set": { "readers.$.someData": 2 }
});
bulk.find({ "_id": id, "readers.user": { "$ne": userId }}).updateOne({
"$push": { "readers": { "user": userId, "someData": 2 } }
});
bulk.execute(function(err,result) {
if (err) callback(err);
console.log("update 2:");
console.log(JSON.stringify( result, undefined, 2));
Test.findById(id,function(err,doc) {
console.log(doc);
callback(err);
});
});
},
// clear array
function(callback) {
Test.findByIdAndUpdate(id,
{ "$pull": { "readers": {} } },
{ "new": true },
function(err,doc) {
console.log('cleared:');
console.log(doc);
callback(err);
}
);
},
// cascade 1 inner condition called on no array match
function(callback) {
console.log('update 3:');
Test.findOneAndUpdate(
{ "_id": id, "readers.user": userId },
{ "$set": { "readers.$.someData": 1 } },
{ "new": true },
function(err,doc) {
if (err) callback(err);
if (!doc) {
console.log('went inner');
Test.findOneAndUpdate(
{ "_id": id, "readers.user": { "$ne": userId } },
{ "$push": { "readers": { "user": userId, "someData": 1 } } },
{ "new": true },
function(err,doc) {
console.log(doc)
callback(err);
}
);
} else {
console.log(doc);
callback(err);
}
}
);
},
// cascade 2 outer condition met on array match
function(callback) {
console.log('update 3:');
Test.findOneAndUpdate(
{ "_id": id, "readers.user": userId },
{ "$set": { "readers.$.someData": 2 } },
{ "new": true },
function(err,doc) {
if (err) callback(err);
if (!doc) {
console.log('went inner');
Test.findOneAndUpdate(
{ "_id": id, "readers.user": { "$ne": userId } },
{ "$push": { "readers": { "user": userId, "someData": 2 } } },
{ "new": true },
function(err,doc) {
console.log(doc)
callback(err);
}
);
} else {
console.log(doc);
callback(err);
}
}
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
Output:
initial state:
{ __v: 0,
name: 'Topic',
_id: 55f60adc1beeff6b0a175e98,
readers: [] }
update 1:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"insertedIds": [],
"nInserted": 0,
"nUpserted": 0,
"nMatched": 1,
"nModified": 1,
"nRemoved": 0,
"upserted": []
}
{ _id: 55f60adc1beeff6b0a175e98,
name: 'Topic',
__v: 0,
readers: [ { user: 55f60adc1beeff6b0a175e97, someData: '1' } ] }
update 2:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"insertedIds": [],
"nInserted": 0,
"nUpserted": 0,
"nMatched": 1,
"nModified": 1,
"nRemoved": 0,
"upserted": []
}
{ _id: 55f60adc1beeff6b0a175e98,
name: 'Topic',
__v: 0,
readers: [ { user: 55f60adc1beeff6b0a175e97, someData: '2' } ] }
cleared:
{ _id: 55f60adc1beeff6b0a175e98,
name: 'Topic',
__v: 0,
readers: [] }
update 3:
went inner
{ _id: 55f60adc1beeff6b0a175e98,
name: 'Topic',
__v: 0,
readers: [ { someData: '1', user: 55f60adc1beeff6b0a175e97 } ] }
update 3:
{ _id: 55f60adc1beeff6b0a175e98,
name: 'Topic',
__v: 0,
readers: [ { someData: '2', user: 55f60adc1beeff6b0a175e97 } ] }

Related

How to count all documents, count unique fields and sum in same query with Mongoose?

I have an addressmodel like this:
const AddressSchema = new Schema({
address: String,
city: String,
postal_code: String,
country: String,
user_id: String,
postalCodeMeters: Number,
});
And I want to know (for a certain user at a certain postal_code):
How many unique addresses have been visited
How many times have the user visited this postal code
How many meters have they traveled
This code works, but I want to do it in one query, not two:
addressrouter.get("/isexplored/:userid/:postalcode",
async (req, res) => {
console.log(req.params.userid)
try {
const addresses = await Address.aggregate(
[
{ $match:{
user_id: req.params.userid,
postal_code: req.params.postalcode
}},
{$group: {
_id: null,
meters: {$sum: "$postalCodeMeters"},
count: { $sum: 1 }
}
}]
)
console.log(addresses)
const uniqueAddresses = (await Address.find(
{
user_id: req.params.userid,
postal_code: req.params.postalcode
}
).distinct('address')).length
res.json({
time: addresses[0].count,
uniqueAddressesVisited: uniqueAddresses,
meters: addresses[0].meters
});
} catch (err) {
console.log(err)
res.json({ message: err });
}
}
)
If I've understood correctly you can do it in a single $group operation.
Check this query where using $addToSet in the $group stage we can get the unique values. And after that use $size into project to know the length.
Address.aggregate([
{
"$match": {
"user_id": req.params.userid,
"postal_code": req.params.postalcode
}
},
{
"$group": {
"_id": null,
"meters": {
"$sum": "$postalCodeMeters"
},
"count": {
"$sum": 1
},
"address": {
"$addToSet": "$address"
}
}
},
{
"$project": {
"_id": 0,
"count": 1,
"meters": 1,
"uniqueAddressesVisited": {
"$size": "$address"
}
}
}
])
Example here

How to improve the query performance it taking 30 sec to execute the query MongoDb

I am using node is along with mongoose.while I am executing this query its taking 30+ sec for execution
I think its due to looping how to improve the performance can anyone guide me I am new to mongoose
companies
.findById(
{
_id: companyProfile,
},
function(err, company) {
if (err) {
return res.status(400).send({
message: "Some Error Occured!",
});
} else {
var responseJson = [];
company.ambulances.forEach(function(doc) {
Gps.find({
$and: [
{
device: doc.deviceId,
},
{
longitude: {
$exists: true,
$ne: "",
},
},
{
locationDate: {
$exists: true,
$ne: "",
},
},
{
latitude: {
$exists: true,
$ne: "",
},
},
],
})
.sort({
$natural: -1,
})
.limit(1)
.exec(function(err, gpsLocations) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err),
});
} else {
responseJson.push({
gps: gpsLocations,
});
if (
company.ambulances.length === responseJson.length
) {
res.json(responseJson);
}
}
});
});
}
},
)
.populate("ambulances");
Well, first try to convert the callbacks to Promises, in order the code to be easier to understand. Now about the speed, you can match all the Gps objects using the $in operator. So the result will be something like that.
try {
const company = await companies.findById({ _id: companyProfile });
const gpsLocations = await Gps.find({
$and: [
{
device: { $in: company.ambulances },
},
{
longitude: {
$exists: true,
$ne: "",
},
},
{
locationDate: {
$exists: true,
$ne: "",
},
},
{
latitude: {
$exists: true,
$ne: "",
},
},
]
}).sort({
$natural: -1,
}).populate("ambulances");
return res.json(gpsLocations.map(gpsLocation => ({
gps: gpsLocation,
})));
} catch(e) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err),
});
}

Find element in array using mongodb

I simply want to count the element in array based on the query. I tried the following command but not solved my problem.
I want to count the element whose TimeStamp is in between "2017-02-17T18:30:00.000Z and "2017-02-18T18:29:59.999Z" on DATA2 array, but it returns only 1.
CODE Executed:
CODE 1
db.ABC.aggregate([{
$match: {
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
}
}, {
$project: {
DATASiz: {
$size: "$DATA2"
},
"has bananas": {
$in: ["DATA2.$.TimeStamp"]
}
}
}], function(err, result) {
console.log(result)
callBack();
})
Code 2
db.abc.find({ $and:[{DATA2: {$exists: true}},{Client_id: "123"},{"DATA2": { $elemMatch: { TimeStamp: { $gte: require('../../modules/getDates').getFromDate(item), $lte: require('../../modules/getDates').getToDate(item) } } }}]
}, function(err, result) {
console.log(JSON.stringify(result))
callBack();
})
Code 3
//db.abc.find //also tried
db.abc.count({
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
},{
"DATA2.$":1
}, function(err, result) {
console.log(result)
callBack();
})
JSON Format:
{
"_id": {
"$oid": "57c7404985737e2c78fde6b3"
},
"ABC": "1304258470",
"Status": "Not Found",
"DATA1": [
{123},{123},{123}
],
"Remark": "Not Found",
"DATA2": [
{
"TimeStamp": "2017-02-18T09:01:43.060Z",
"NdrStatus": "Door Locked",
},
{
"TimeStamp": "2017-02-18T08:09:43.347Z",
"NdrStatus": "HOLD",
},
{
"TimeStamp": "2017-02-20T08:09:43.347Z",
"NdrStatus": "HOLD",
}
]
}
Result:
I am getting the first element of DATA2 using CODE 3 but I know that as per the query 2 elements are to return.
I expect 2 as in count.
Also used $unwind $redact
Thanks in advance.
You can use the $filter and $size operators for this:
var start = require('../../modules/getDates').getFromDate(item),
end = require('../../modules/getDates').getToDate(item);
db.ABC.aggregate([
{
"$match": {
"DATA2": { "$exists": true },
"DATA2.TimeStamp": { "$gte": start, "$lte": end },
"Client_id": "123"
}
},
{
"$project": {
"DATASiz": {
"$size": {
"$filter": {
"input": "$DATA2",
"as": "item",
"cond": {
"$and": [
{ "$gte": ["$$item.TimeStamp", start] },
{ "$lte": ["$$item.TimeStamp", end] }
]
}
}
}
}
}
}
], function(err, result) {
console.log(result);
callBack();
});

Node JS Mongoose PULL query

I find many great answers here on SO like this answer an this. But i can not get it to work...
I tried ObjectId("55cf816559d2fc8d0e6c14a8") in the query where the id is.
This query works when robotmongo run it:
db.getCollection('events').update(
{ "_id": ObjectId("55cf816559d2fc8d0e6c14a8") },
{ "$pull": { "workers" : { "_id": ObjectId("55cf89ac7cba1d0a10ca86c7")}}},
false,
true
)
Side note, what is the false,true for?
Here is my current code
event.update(
{'_id': "55cf816559d2fc8d0e6c14a8"},
{ "$pull": { "workers" : {_id: "55cf89ac7cba1d0a10ca86c7"}}},
function(err, result) {
console.log(err);
console.log(result);
}
);
I do not get any errors and the result is equal to 1.
Works for me. You must be doing something differently and incorrectly:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var workerSchema = new Schema({
name: String
});
var eventSchema = new Schema({
name: String,
workers: [workerSchema]
});
var Event = mongoose.model( 'Event', eventSchema );
async.series(
[
function(callback) {
Event.remove({},function(err) {
callback(err);
});
},
function(callback) {
var event = new Event({
_id: "55cf816559d2fc8d0e6c14a8",
name: "Great thing"
});
event.workers.push({
_id: "55cf89ac7cba1d0a10ca86c7",
name: "Worker1"
});
event.save(function(err,event) {
console.log(event);
callback(err);
});
},
function(callback) {
Event.findOneAndUpdate(
{ "_id": "55cf816559d2fc8d0e6c14a8" },
{ "$pull": { "workers": { "_id": "55cf89ac7cba1d0a10ca86c7" } } },
{ "new": true },
function(err,event) {
console.log(event)
callback(err);
}
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
With the expected output:
{ __v: 0,
_id: 55cf816559d2fc8d0e6c14a8,
name: 'Great thing',
workers: [ { _id: 55cf89ac7cba1d0a10ca86c7, name: 'Worker1' } ] }
{ _id: 55cf816559d2fc8d0e6c14a8,
name: 'Great thing',
__v: 0,
workers: [] }

Mongoose: Not able to add/push a new object to an array with $addToSet or $push

I use Nodejs, Hapijs and Mongoose.
I 've a schema and model as follows.
var schema = {
name: {
type: String,
required: true
},
lectures: {}
};
var mongooseSchema = new mongoose.Schema(schema, {
collection: "Users"
});
mongoose.model("Users", mongooseSchema);
For some reason, I need to keep "lectures"
as mixed type.
While saving/creating a document I create a nested property lectures.physics.topic[] where topic is an array.
Now, I'm trying to add/push a new object to "lectures.physics.topic" using $addToSet or $push.
userModel.findByIdAndUpdateAsync(user._id, {
$addToSet: {
"lectures.physics.topic": {
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
}
});
But the document is simply not getting updated. I tried using $push too. Nothing worked. What could be the problem?
I tried to another approach using mongoclient , to update the db directly .It works please find the below code which works
db.collection("Users").update({
"_id": user._id
}, {
$addToSet: {
"lectures.physics.topic": {
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
}
}, function(err, result) {
if (err) {
console.log("Superman!");
console.log(err);
return;
}
console.log(result);
});
I have to start the mongo client every time a request is hit.This is not a feasible solution.
Mongoose loses the ability to auto detect and save changes made on Mixed types so you need to "tell" it that the value of a Mixed type has changed by calling the .markModified(path) method of the document passing the path to the Mixed type you just changed:
doc.mixed.type = 'changed';
doc.markModified('mixed.type');
doc.save() // changes to mixed.type are now persisted
In your case, you could use findById() method to make your changes by calling the addToSet() method on the topic array and then triggering the save() method to persist the changes:
userModel.findById(user._id, function (err, doc){
var item = {
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
};
doc.lectures.physics.topic.addToSet(item);
doc.markModified('lectures');
doc.save() // changes to lectures are now persisted
});
I'd be calling "bug" on this. Mongoose is clearly doing the wrong thing as can be evidenced in the logging as shown later. But here is a listing that calls .findOneAndUpdate() from the native driver with the same update you are trying to do:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/school');
mongoose.set('debug',true);
var userSchema = new Schema({
name: {
type: String,
required: true
},
lectures: { type: Schema.Types.Mixed }
});
var User = mongoose.model( "User", userSchema );
function logger(data) {
return JSON.stringify(data, undefined, 2);
}
async.waterfall(
[
function(callback) {
User.remove({},function(err) {
callback(err);
});
},
function(callback) {
console.log("here");
var user = new User({ "name": "bob" });
user.save(function(err,user) {
callback(err,user);
});
},
function(user,callback) {
console.log("Saved: %s", logger(user));
User.collection.findOneAndUpdate(
{ "_id": user._id },
{
"$addToSet": {
"lectures.physics.topic": {
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
}
},
{ "returnOriginal": false },
function(err,user) {
callback(err,user);
}
);
}
],
function(err,user) {
if (err) throw err;
console.log("Modified: %s", logger(user));
mongoose.disconnect();
}
);
This works perfectly with the result:
Saved: {
"__v": 0,
"name": "bob",
"_id": "55cda1f5b5ee8b870e2f53bd"
}
Modified: {
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": "55cda1f5b5ee8b870e2f53bd",
"name": "bob",
"__v": 0,
"lectures": {
"physics": {
"topic": [
{
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
]
}
}
},
"ok": 1
}
You neeed to be careful here as native driver methods are not aware of the connection status like the mongoose methods are. So you need to be sure a connection has been made by a "mongoose" method firing earlier, or wrap your app in a connection event like so:
mongoose.connection.on("connect",function(err) {
// start app in here
});
As for the "bug", look at the logging output from this listing:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/school');
mongoose.set('debug',true);
var userSchema = new Schema({
name: {
type: String,
required: true
},
lectures: { type: Schema.Types.Mixed }
});
var User = mongoose.model( "User", userSchema );
function logger(data) {
return JSON.stringify(data, undefined, 2);
}
async.waterfall(
[
function(callback) {
User.remove({},function(err) {
callback(err);
});
},
function(callback) {
console.log("here");
var user = new User({ "name": "bob" });
user.save(function(err,user) {
callback(err,user);
});
},
function(user,callback) {
console.log("Saved: %s", logger(user));
User.findByIdAndUpdate(
user._id,
{
"$addToSet": {
"lectures.physics.topic": {
"name": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
}
},
{ "new": true },
function(err,user) {
callback(err,user);
}
);
}
],
function(err,user) {
if (err) throw err;
console.log("Modified: %s", logger(user));
mongoose.disconnect();
}
);
And the logged output with mongoose logging:
Mongoose: users.remove({}) {}
here
Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda2d2462283c90ea3f1ad"), __v: 0 })
Saved: {
"__v": 0,
"name": "bob",
"_id": "55cda2d2462283c90ea3f1ad"
}
Mongoose: users.findOne({ _id: ObjectId("55cda2d2462283c90ea3f1ad") }) { new: true, fields: undefined }
Modified: {
"_id": "55cda2d2462283c90ea3f1ad",
"name": "bob",
"__v": 0
}
So in true "What the Fudge?" style, there is a call there to .findOne()? Which is not what was asked. Moreover, nothing is altered in the database of course because the wrong call is made. So even the { "new": true } here is redundant.
This happens at all levels with "Mixed" schema types.
Personally I would not nest within "Objects" like this, and just make your "Object keys" part of the standard array as additional properties. Both MongoDB and mongoose are much happier with this, and it is much easier to query for information with such a structure.
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/school');
mongoose.set('debug',true);
var lectureSchema = new Schema({
"subject": String,
"topic": String,
"day": String,
"faculty": String
});
var userSchema = new Schema({
name: {
type: String,
required: true
},
lectures: [lectureSchema]
});
var User = mongoose.model( "User", userSchema );
function logger(data) {
return JSON.stringify(data, undefined, 2);
}
async.waterfall(
[
function(callback) {
User.remove({},function(err) {
callback(err);
});
},
function(callback) {
console.log("here");
var user = new User({ "name": "bob" });
user.save(function(err,user) {
callback(err,user);
});
},
function(user,callback) {
console.log("Saved: %s", logger(user));
User.findByIdAndUpdate(
user._id,
{
"$addToSet": {
"lectures": {
"subject": "physics",
"topic": "Fluid Mechanics",
"day": "Monday",
"faculty": "Nancy Wagner"
}
}
},
{ "new": true },
function(err,user) {
callback(err,user);
}
);
}
],
function(err,user) {
if (err) throw err;
console.log("Modified: %s", logger(user));
mongoose.disconnect();
}
);
Output:
Mongoose: users.remove({}) {}
here
Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b"), lectures: [], __v: 0 })
Saved: {
"__v": 0,
"name": "bob",
"_id": "55cda4dc40f2a8fb0e5cdf8b",
"lectures": []
}
Mongoose: users.findAndModify({ _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b") }) [] { '$addToSet': { lectures: { faculty: 'Nancy Wagner', day: 'Monday', topic: 'Fluid Mechanics', subject: 'physics', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8c") } } } { new: true, upsert: false, remove: false }
Modified: {
"_id": "55cda4dc40f2a8fb0e5cdf8b",
"name": "bob",
"__v": 0,
"lectures": [
{
"faculty": "Nancy Wagner",
"day": "Monday",
"topic": "Fluid Mechanics",
"subject": "physics",
"_id": "55cda4dc40f2a8fb0e5cdf8c"
}
]
}
So that works fine, and you don't need to dig to the native methods just to make it work.
Properties of an array make this much easy to query and filter, as well as "aggregate" information across the data, which for all of those MongoDB likes a "strict path" to reference all information. Otherwise you are diffing to only "specific keys", and those cannot be indexed or really searched without mentioning every possible "key combination".
Properties like this are a better way to go. And no bugs here.

Resources