I have the following setup.
The me = is incoming data from the request but since it's not used in this example I am skipping the info.
Added the findAndUpdate I am trying to do. Why is there an insert being done on findAndUpdate instead of an update?
app.js
mongoose.connect("mongodb://localhost/time_report");
var reportSchema = new mongoose.Schema({
name: String,
month: String,
date: String,
hours: Number,
dayNumber: Number,
day: String
});
var time = mongoose.model("time", reportSchema);
Query:
app.get("/test", function(req, res) {
var me = new time({
name: info[i + 3],
month: info[i + 1],
date: info[i + 2],
hours: info[i],
dayNumber: info[i + 4],
day: info[i + 5]
});
time.findOneAndUpdate(query, update, options, function(err, data) {
if (err) {
console.log(err);
}
console.log("data: " + data);
found = true;
});
}
..... More stuff and listener
In MongoDB:
{ "_id" : ObjectId("598d71b20f47692f48eb7393"), "name" : "jocke", "month" : "2017-08", "date" : "2017-08-01", "hours" : 8, "dayNumber" : 2, "day" : "Tuesday", "__v" : 0 }
Mongoose debug:
[0;36mMongoose: times.findAndModify({ date: '2017-08-31' }, [], { '$set': { hours: null } }, { new: false, upsert: false, fields: {} })
[0;36mMongoose: times.insert({ name: '', month: '2017-08', date: '2017-08-31', hours: null, dayNumber: 4, day: 'Thursday', _id: ObjectId("598d7ef69386343b3035192f"), __v: 0 })
If you have the mongoose model exported just use below code
var time = require('./models/time');
app.get('/test', function(req, res){
// change the search object as per your need like month=2018/07
time.findOne(req.body, function(err, doc){
if(err) return handleError(err);
res.send(doc)
})
})
Related
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
if(err) console.log(err);
console.log("DOC " + doc)
if(doc.status) {
// FOUND ROOM SATTUS IS TRUE LOGIC
console.log(doc);
// return callback(true)
}
});
Above query will return to me the actual document that's updated or inserted but I can't check exactly which one it is. If I do an update instead of findOneandUpdate I'm returned this
{
ok: 1,
nModified: 0,
n: 1,
upserted: [ { index: 0, _id: 55df883dd5c3f7cda6f84c78 } ]
}
How do I return both the document and the write result or at least the upserted field from the write result.
As of 8 August 2019 (Mongoose Version 5.6.9), the property to set is "rawResult" and not "passRawResult":
M.findOneAndUpdate({}, obj, {new: true, upsert: true, rawResult:true}, function(err, d) {
if(err) console.log(err);
console.log(d);
});
Output:
{ lastErrorObject:
{ n: 1,
updatedExisting: false,
upserted: 5d4befa6b44b48c3f2d21c75 },
value: { _id: 5d4befa6b44b48c3f2d21c75, rating: 4, review: 'QQQ' },
ok: 1 }
Notice also the result is returned as the second parameter and not the third parameter of the callback. The document can be retrieved by d.value.
Version 4.1.10 of Mongoose has an option called passRawResult which if set to true causes the raw parameter to be passed. Leaving out this option seems to default to false and cause raw to always be undefined:
passRawResult: if true, passes the raw result from the MongoDB driver
as the third callback parameter
http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate
Alright so my main problem was that I couldn't get the _id of the document I inserted without not being able to check whether if it was updated/found or inserted. However I learned that you can generate your own Id's.
id = mongoose.Types.ObjectId();
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {_id: id, status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
if(err) console.log(err);
if(doc === null) {
// inserted document logic
// _id available for inserted document via id
} else if(doc.status) {
// found document logic
}
});
Update
Mongoose API v4.4.8
passRawResult: if true, passes the raw result from the MongoDB driver as the third callback parameter.
I'm afraid Using FindOneAndUpdate can't do what you whant because it doesn't has middleware and setter and it mention it the docs:
Although values are cast to their appropriate types when using the findAndModify helpers, the following are not applied:
defaults
Setters
validators
middleware
http://mongoosejs.com/docs/api.html search it in the findOneAndUpdate
if you want to get the docs before update and the docs after update you can do it this way :
Model.findOne({ name: 'borne' }, function (err, doc) {
if (doc){
console.log(doc);//this is ur document before update
doc.name = 'jason borne';
doc.save(callback); // you can use your own callback to get the udpated doc
}
})
hope it helps you
I don't know how this got completely off track, but there as always been a "third" argument response to all .XXupdate() methods, which is basically the raw response from the driver. This always tells you whether the document is "upserted" or not:
Chatrooms.findOneAndUpdate(
{ "Roomname": room.Roomname },
{ "$setOnInsert": {
"status": true, "userNum": 1
}},
{ "new": true, "upsert": true },
function(err, doc,raw) {
if(err) console.log(err);
// Check if upserted
if ( raw.lasErrorObject.n == 1 && !raw.lastErrorObject.updatedExisting ) {
console.log("upserted: %s", raw.lastErrorObject.upserted);
}
console.log("DOC " + doc)
if (doc.status) {
// FOUND ROOM SATTUS IS TRUE LOGIC
console.log(doc);
// return callback(true)
}
});
Which will tell you the _id of the document that was just upserted.
From something like this in the "raw" response:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
status: true,
userNum: 1
__v: 0 },
ok: 1 }
Complete reproducible listing:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var testSchema = new Schema({
name: String
});
var Test = mongoose.model('Test', testSchema, 'test');
async.series(
[
function(callback) {
Test.remove({},callback);
},
function(callback) {
async.eachSeries(
["first","second"],
function(it,callback) {
console.log(it);
Test.findOneAndUpdate(
{ "name": "Bill" },
{ "$set": { "name": "Bill" } },
{ "new": true, "upsert": true },
function(err,doc,raw) {
console.log(raw),
console.log(doc),
callback(err);
}
);
},
callback
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
Which outputs:
first
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e2a92328f7d03a06a2dd6b },
value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
second
{ lastErrorObject: { updatedExisting: true, n: 1 },
value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
I am Facing the error at the time of insert the query.
Error is "db.collection.insert is not a function"
My database schema is like this
'use strict';
var mongoose = require('mongoose');
//Schema
var ABCSchema = mongoose.Schema({
sequenceid: {
type: Number
},
A: {
type: Array,
default: []
},
B: {
type: Array,
default: []
},
C: {
type: Array,
default: []
},
D: {
type: Array,
default: []
}
});
var ABC = module.exports = mongoose.model('ABC', ABCSchema);
Now I want to enter the data which looks like this.
It's just a sample by which you people can understand that how I can Store the value.
{
"_id" : ObjectId("5a2e2eb9104cce1b58385620"),
"sequenceid": 1,
"A" : [
{
"apple" : "red",
"count" : 24
}
],
"B" : [],
"C" : [],
"D" : [],
"__v" : 0
}
Now what I am trying to code is like this
ABC.insert({'sequenceid': 1, 'A': {'apple': 'red', 'count': 24}}, function(error, data){
console.log(data);
});
As #Manjeet Thakur pointed out what you are trying to insert at "A" is and object and not an Array
Change it to array
{
"A": [{
"apple": "red",
"count": 24
}],
"sequenceid": 1
}
Also you need to instantiate your model and save it
var abc = new ABC({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}]});
abc.save()
//or
ABC.create({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}]}, function (err, small) {
//if (err) return throw err;
// saved!
})
'use strict';
var mongoose = require('mongoose');
//Schema
var ABCSchema = mongoose.Schema({
sequenceid: {
type: Number
},
A: {
type: Array,
default: []
},
B: {
type: Array,
default: []
},
C: {
type: Array,
default: []
},
D: {
type: Array,
default: []
}
});
var ABC = module.exports = mongoose.model('ABC', ABCSchema);
// here now collection is ABC (name of collection)
ABC.insert({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}] }, function(error, data){
console.log(data);
});
Here is a schema that I am working on.
var testSchema = mongoose.Schema({
userCreated : {
type : mongoose.Schema.Types.ObjectId,
ref : "User"
},
points : {type: Number, default: 0},
numVotes : {type: Number, default: 0},
createdAt : Date,
updatedAt : Date,
}, { timestamps : true });
Now, I am trying to write a function that will increment two fields on this document (points and numVotes, as well as an additional points field that exists on the user schema.
Here is my attempt.
testSchema.statics.incrementTest = function(id, ...) {
this.findByIdAndUpdate(id, {$inc : {
points : 5,
numVotes : 1,
'userCreated.points' : 5
}}).exec();
}
Now, this code that I have written does not work. However, when I comment out the 'userCreated.points' : 5 line, the other two fields do increment as expected. My question is, what is the best way using mongoose to update the fields on a document and the fields on a subdocument at the same time?
The data here is contained in different collections, so no single update statement is able to increment counters in both at the same time.
In order to get a consistent view you are going to need to "chain" your update statements and use the return results of each to build the response.
Depending on your needs you can either use a Promise with this:
testSchema.statics.incrementTest = function(id) {
var self = this;
return new Promise(function(resolve,reject) {
self.findByIdAndUpdate(
id,
{
"$inc": {
"points": 5,
"numVotes": 1
}
},
{ "new": true }
).then(function(test) {
var userModel = test.schema.path("userCreated").options.ref;
mongoose.model(userModel).findByIdAndUpdate(
test.userCreated,
{ "$inc": { "points": 5 } },
{ "new": true }
).then(function(user) {
test.userCreated = user;
resolve(test);
})
}).catch(reject)
})
};
Which you can then invoke on your model:
Test.incrementTest("56fe279d363ce91765d9e39e").then(function(test) {
console.log(JSON.stringify(test,undefined,2));
}).catch(function(err) {
throw err;
})
Or you can use async.waterfall from the async library if that suits you better:
testSchema.statics.incrementTest = function(id,callback) {
var self = this;
async.waterfall(
[
function(callback) {
self.findByIdAndUpdate(
id,
{
"$inc": {
"points": 5,
"numVotes": 1
}
},
{ "new": true },
callback
)
},
function(err,test) {
if (err) callback(err);
var userModel = test.schema.path("userCreated").options.ref;
mongoose.model(userModel).findByIdAndUpdate(
test.userCreated,
{ "$inc": { "points": 5 } },
{ "new": true },
function(err,user) {
if ( typeof(user) !== "undefined" )
test.userCreated = user;
callback(err,test);
}
);
}
],
callback
);
};
Which has a similar usage:
Test.incrementTest("56fe279d363ce91765d9e39e",function(err,test) {
if (err) throw err;
console.log(JSON.stringify(test,undefined,2));
})
Both should be giving you a result back that shows the incremented data in both objects for both collections:
{ points: 5,
numVotes: 1,
__v: 0,
userCreated: { points: 5, __v: 0, _id: 56ff1aa6dba6d13e798fc894 },
createdAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT),
updatedAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT),
_id: 56fe279d363ce91765d9e39e }
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
if(err) console.log(err);
console.log("DOC " + doc)
if(doc.status) {
// FOUND ROOM SATTUS IS TRUE LOGIC
console.log(doc);
// return callback(true)
}
});
Above query will return to me the actual document that's updated or inserted but I can't check exactly which one it is. If I do an update instead of findOneandUpdate I'm returned this
{
ok: 1,
nModified: 0,
n: 1,
upserted: [ { index: 0, _id: 55df883dd5c3f7cda6f84c78 } ]
}
How do I return both the document and the write result or at least the upserted field from the write result.
As of 8 August 2019 (Mongoose Version 5.6.9), the property to set is "rawResult" and not "passRawResult":
M.findOneAndUpdate({}, obj, {new: true, upsert: true, rawResult:true}, function(err, d) {
if(err) console.log(err);
console.log(d);
});
Output:
{ lastErrorObject:
{ n: 1,
updatedExisting: false,
upserted: 5d4befa6b44b48c3f2d21c75 },
value: { _id: 5d4befa6b44b48c3f2d21c75, rating: 4, review: 'QQQ' },
ok: 1 }
Notice also the result is returned as the second parameter and not the third parameter of the callback. The document can be retrieved by d.value.
Version 4.1.10 of Mongoose has an option called passRawResult which if set to true causes the raw parameter to be passed. Leaving out this option seems to default to false and cause raw to always be undefined:
passRawResult: if true, passes the raw result from the MongoDB driver
as the third callback parameter
http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate
Alright so my main problem was that I couldn't get the _id of the document I inserted without not being able to check whether if it was updated/found or inserted. However I learned that you can generate your own Id's.
id = mongoose.Types.ObjectId();
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {_id: id, status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
if(err) console.log(err);
if(doc === null) {
// inserted document logic
// _id available for inserted document via id
} else if(doc.status) {
// found document logic
}
});
Update
Mongoose API v4.4.8
passRawResult: if true, passes the raw result from the MongoDB driver as the third callback parameter.
I'm afraid Using FindOneAndUpdate can't do what you whant because it doesn't has middleware and setter and it mention it the docs:
Although values are cast to their appropriate types when using the findAndModify helpers, the following are not applied:
defaults
Setters
validators
middleware
http://mongoosejs.com/docs/api.html search it in the findOneAndUpdate
if you want to get the docs before update and the docs after update you can do it this way :
Model.findOne({ name: 'borne' }, function (err, doc) {
if (doc){
console.log(doc);//this is ur document before update
doc.name = 'jason borne';
doc.save(callback); // you can use your own callback to get the udpated doc
}
})
hope it helps you
I don't know how this got completely off track, but there as always been a "third" argument response to all .XXupdate() methods, which is basically the raw response from the driver. This always tells you whether the document is "upserted" or not:
Chatrooms.findOneAndUpdate(
{ "Roomname": room.Roomname },
{ "$setOnInsert": {
"status": true, "userNum": 1
}},
{ "new": true, "upsert": true },
function(err, doc,raw) {
if(err) console.log(err);
// Check if upserted
if ( raw.lasErrorObject.n == 1 && !raw.lastErrorObject.updatedExisting ) {
console.log("upserted: %s", raw.lastErrorObject.upserted);
}
console.log("DOC " + doc)
if (doc.status) {
// FOUND ROOM SATTUS IS TRUE LOGIC
console.log(doc);
// return callback(true)
}
});
Which will tell you the _id of the document that was just upserted.
From something like this in the "raw" response:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
status: true,
userNum: 1
__v: 0 },
ok: 1 }
Complete reproducible listing:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var testSchema = new Schema({
name: String
});
var Test = mongoose.model('Test', testSchema, 'test');
async.series(
[
function(callback) {
Test.remove({},callback);
},
function(callback) {
async.eachSeries(
["first","second"],
function(it,callback) {
console.log(it);
Test.findOneAndUpdate(
{ "name": "Bill" },
{ "$set": { "name": "Bill" } },
{ "new": true, "upsert": true },
function(err,doc,raw) {
console.log(raw),
console.log(doc),
callback(err);
}
);
},
callback
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
Which outputs:
first
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e2a92328f7d03a06a2dd6b },
value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
second
{ lastErrorObject: { updatedExisting: true, n: 1 },
value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
I try to update a document with mongoose and it fails. The query I can successful execute directly in Mongo is like:
db.orders.update(
{
orderId: 1014428,
'delivery.items.id': '5585d77c714a90fe0fc2fcb4'
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}
)
When I try to run the following update command with mongoose:
this.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
I see the following error:
{ [MongoError: cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})]
name: 'MongoError',
message: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})',
index: 0,
code: 16837,
errmsg: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})' }
The raw response from Mongo was { ok: 0, n: 0, nModified: 0 }
I tried so many things. Any advice on this?
As requested the schema:
var Order = new Schema({
orderId: Number,
orderDate: String,
customerName: String,
state: Number,
delivery: {
items: {type: Array, default: []},
state: { type: Number, default: 0 }
}
});
TL;DR: use your model Order instead of an instance this when doing more advanced queries:
Orders.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
Explanation:
Mapping differences between Model.update() and Document.update().
The using the model, then Model.update() will be used and
Model.update(conditions, doc, options, callback)
will be mapped to:
db.collection.update(query = conditions, update = doc, options)
When using an instance instead your calling Document.update() and
Document.update(doc, options, callback)
will be mapped to the following:
db.collection.update(query = {_id: _id}, update = doc, options)
Don't know if this helps, but in this question the O.P. had a similar issue with mongoose 3.6.15, and claimed it was solved in 3.8.22
EDIT: In the linked question, the O.P. had the following working on mongodb
db.orchards.update(
({"orchardId": ObjectId("5391c137722b051908000000")},
{"trees" : { $elemMatch: {"name":"apple"}}}),
{ $push: { "trees.$.fruits": ObjectId("54c542c9d900000000001234") }})
But this not working in mongoose:
orchards.update(
({"orchardId": ObjectId.fromString(orchard.id)},
{"trees" : {$elemMatch: {"name": "apple"}}}),
{$push: {"trees.$.fruits": ObjectId("54c542c9d900000000001234") }},function(err, data){ ...
In a comment, he said the issue was solved switching to mongoose 3.8.22