losing my mind here for something for a MongoDB document update with Mongoose, not reporting any error but not actually updating successfully.
I have this schema:
/**
* Branch Schema
*/
let BranchSchema = new Schema({
name: String,
domain: String,
email: String,
bm: { type: Schema.ObjectId, ref: 'User' },
st: [{ type: Schema.ObjectId, ref: 'User' }],
stockCurrent: {
paper: Schema.Types.Object,
ink: Schema.Types.Object
},
stockNeeded: {
paper: Schema.Types.Object,
ink: Schema.Types.Object
},
}, { versionKey: false, usePushEach: true });
mongoose.model('Branch', BranchSchema);
Trying to update stockCurrent, using this logic:
Branch.findById(config.branch.id, function (err, branch) {
if (err) {
res.status(422).send({
message: 'הסניף לא נמצא'
});
} else {
console.log(branch);
Object.keys(req.body.stock).forEach(function (type) {
Object.keys(req.body.stock[type]).forEach(function (code) {
if (req.body.stock[type][code] > 0) {
if (typeof branch.stockCurrent[type][code] === 'undefined') {
branch.stockCurrent[type][code] = 0;
}
branch.stockCurrent[type][code] += req.body.stock[type][code];
}
});
});
console.log(branch);
branch.save(function (err, updated) {
console.log("err: " + err);
if (err) {
stock.remove();
res.status(422).send({
message: 'שגיאה בשמירת מלאי'
});
} else {
console.log(updated);
res.send({
message: 'מלאי נוסף בהצלחה'
});
}
});
}
});
I get to to success part, having my console log this:
{
"_id":5dd276a6bcc29a13789fcecb,
"name":"בצלאל ארכיטקטורה",
"domain":"bezalel.eazix.io",
"email":"eazix.1.bezalel#gmail.com",
"bm":5cdd2130d192ea03a87d2dfd,
"stockNeeded":{
"ink":{
"GY":2,
"PM":2,
"M":2,
"MBK":2,
"PBK":2,
"PC":2,
"Y":2,
"C":2,
"waste":2
},
"paper":{
"COATED":5,
"PLAIN":5,
"PHOTO":3
}
},
"stockCurrent":{
"paper":{
"PLAIN":0
},
"ink":{
"waste":0
}
},
"st":[
]
}{
"_id":5dd276a6bcc29a13789fcecb,
"name":"בצלאל ארכיטקטורה",
"domain":"bezalel.eazix.io",
"email":"eazix.1.bezalel#gmail.com",
"bm":5cdd2130d192ea03a87d2dfd,
"stockNeeded":{
"ink":{
"GY":2,
"PM":2,
"M":2,
"MBK":2,
"PBK":2,
"PC":2,
"Y":2,
"C":2,
"waste":2
},
"paper":{
"COATED":5,
"PLAIN":5,
"PHOTO":3
}
},
"stockCurrent":{
"paper":{
"COATED":1,
"PHOTO":2,
"PLAIN":0
},
"ink":{
"PM":1,
"waste":0
}
},
"st":[
]
}**"err":null**{
"_id":5dd276a6bcc29a13789fcecb,
"name":"בצלאל ארכיטקטורה",
"domain":"bezalel.eazix.io",
"email":"eazix.1.bezalel#gmail.com",
"bm":5cdd2130d192ea03a87d2dfd,
"stockNeeded":{
"ink":{
"GY":2,
"PM":2,
"M":2,
"MBK":2,
"PBK":2,
"PC":2,
"Y":2,
"C":2,
"waste":2
},
"paper":{
"COATED":5,
"PLAIN":5,
"PHOTO":3
}
},
"stockCurrent":{
"paper":{
"COATED":1,
"PHOTO":2,
"PLAIN":0
},
"ink":{
"PM":1,
"waste":0
}
},
"st":[
]
}
I can see the here the initial state, the updated version before saving, and the the err:null, and the allegedly updated document.
but alas! the document wasn't really updated. it remains the same.
I have tried many things, searching and looking for similar cases, checking my schema, adding useStrict:false to the schema, nothing helps.
Mongoose ver 4.13.20, Mongodb ver 3.6.17
SOS
Dor
I'm guessing the SchemaTypes are the problem? In Mongoose 4.x, these are the only valid SchemaTypes:
String
Number
Date
Buffer
Boolean
Mixed
Objectid
Array
Notice that Mixed is an option but not Object. You need to tell Mongoose that you updated a Mixed field using model.markModified('pathName'). See the Mixed docs.
So in your case, the code below may fix the issue:
branch.markModified('stockCurrent');
branch.save(function (err, updated) {
// ...
Related
I am working with AWS DynamoDB and Dynamoose trying to fetch records using Scan function, but facing an issue that is not recognizable for me.
Stragenly, it's able to fetch records from another table in the same way and successfully get the records.
Here's my Code:
const vehicleMasterSchema = new dynamoose.Schema({
"id": String,
"customer_account_number": String,
"fuel_type": String,
"make": String,
"model": String,
"odometer_gatex": String,
"plate_no": String,
"rfid_gatex": String,
"sales_agreement_id": String,
"vehicle_category": String,
"vehicle_id": String,
}, {
"timestamps": {
"createdAt": "create_date",
"updatedAt": null // updatedAt will not be stored as part of the timestamp
}
});
const vehicleMasterModel = dynamoose.model("vehicle_master", vehicleMasterSchema, { "create": false });
router.post('/getFuelingStatus', (req, res) => {
var companyInfo = req.body;
try {
console.log(typeof vehicleMasterModel);
vehicleMasterModel.scan("customer_account_number").eq(companyInfo.customerId).exec((error, results) => {
if (error) {
console.error(error);
} else {
res.json(results);
}
});
} catch (error) {
res.json(error);
}
});
The TypeMismatch error is coming up only for this model same code is working for the other table.
Console Error
My Table
This appears to be related to this github issue on Dyanmoose
My guess is that the problem could be related with the name of your attribute, model.
In fact, this is the actual case: the following code, extracted from the source code in Document.ts is the one which is overwriting your model property:
Object.defineProperty(this, "model", {
"configurable": false,
"value": model
});
This is how the Document looks like before:
And after the execution of the aforementioned code:
This code is executed when processing the Scan exec function in DocumentRetriever.ts when the library maps every Item returned by DynamoDB to their internal Document representation, exactly in this line of code:
const array: any = (await Promise.all(result.Items.map(async (item) => await new this.internalSettings.model.Document(item, {"type": "fromDynamo"}).conformToSchema({"customTypesDynamo": true, "checkExpiredItem": true, "saveUnknown": true, "modifiers": ["get"], "type": "fromDynamo"})))).filter((a) => Boolean(a));
The error you reported is a consequence of that change when the type of the returned Item is checked against your schema model in the checkTypeFunction:
const {isValidType, matchedTypeDetails, typeDetailsArray} = utils.dynamoose.getValueTypeCheckResult(schema, value, genericKey, settings, {"standardKey": true, typeIndexOptionMap});
if (!isValidType) {
throw new Error.TypeMismatch(`Expected ${key} to be of type ${typeDetailsArray.map((detail) => detail.dynamicName ? detail.dynamicName() : detail.name.toLowerCase()).join(", ")}, instead found type ${typeof value}.`);
...
Please, try a different name, I think it will work properly.
Schema must be like this :
const ImageGalleryFoldersSchema = new Schema({
key: {
type: String,
hashKey: true,
required: true,
},
displayName: {
type: String,
required: true,
},
parentFolderKey: {
type: String,
required: false,
},
isActive: {
type: Boolean,
default: true,
required: false,
},
}, {
timestamps: true,
});
Maybe your problem is caused due to asynchronous behaviour.
To be more specific, I think that by the time you call the "scan"-function-chain the body-request has not been finished. However, due to the nature of Hoisting, the object "companyInfo" was already being initialised before you enter the function-call.
Therefore, you may get the specified "TypeMismatch"-error.
Could you please try implementing the following async/await-structure and tell me if this helps:
router.post('/getFuelingStatus', async (req, res) => {
var companyInfo = await req.body;
try {
console.log(typeof vehicleMasterModel);
vehicleMasterModel.scan("customer_account_number").eq(companyInfo.customerId).exec((error, results) => {
if (error) {
console.error(error);
} else {
res.json(results);
}
});
} catch (error) {
res.json(error);
}
});
var UserSchema = new mongoose.Schema({
//Irrelevant code
profile:
{
requests: [{ sender: String, id: String, hasSelected: Boolean, value: Boolean}]
}
});
That object is to keep track of friend request, I want it to get completely deleted from the requests array once it has been accepted or declined. I have tried a whole bunch of stuff but nothing is deleting it. Currently have this code:
User.updateOne({ id: user.id },
{ "$pull": { "profile": { "requests": { "id": targetId } } } },
{ "multi": true },
function(err,status) {
if(err){console.log("Could not delete the friend request");}
else{
console.log("Sucessfully deleted friend request from: " + user.name);}
}
);
It always says it was deleted on the log, but when I check on mongoDB the request is still there.
try $elemMatch to remove the specific object.
User.updateOne(
{ id: user.id },
{ $pull: { "profile.requests": { $elemMatch: { id: targetId } } } },
{ multi: true },
function (err, status) {
if (err) {
console.log("Could not delete the friend request");
} else {
console.log("Sucessfully deleted friend request from: " + user.name);
}
}
);
I have this model
student: {
package:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Package',
},
history: [
{
package: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Package',
},
orderDate: {
type: Date,
default: new Date().toLocaleDateString('id'),
},
Status: {
type: String,
default: 'Pending',
},
},
],
}
What I want to do is that I want to update Student.package and Student.history in 1 pass
I create this method in my model
StudentSchema.methods.updatePackage= function(idPackage) {
this.package = idPackage;
return this.save();
};
StudentSchema.methods.updateHistory= function(idPackage) {
this.history.push(idPackage);
return this.save();
};
and I'm trying to do something like this in my controller
buyPack: async (req, res, next) => {
try {
let dataStudent = await Student.findById('5b83443040e3751bb4e32a21');
await dataStudent.updatePackage(req.body);
await dataStudent.updateHistory(req.body);
return res.json(dataStudent);
} catch (err) {
console.log(err);
next(err);
}
},
I think the first and second methods are wrong, but I have tried to figure it out in almost half of day, but still no luck. What is the best way to achieve my goals?
Do I make my model wrong? or do the methods I created are wrong?
Mongoose model rename with plural .. and you refer with singular with "S", "Package" change it to "Packages"
Here are my user and product schemas:
const productSchema = new Schema({
//...
addedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "users"
}
});
const userSchema = new Schema({
//...
addedItems: [{
type: mongoose.Schema.ObjectId,
ref: "products"
}]
});
mongoose.model("products", productSchema);
mongoose.model("users", userSchema);
In my Node back end route I do this query:
User.findOneAndUpdate(
{ _id: req.body.id },
{ $push: { addedItems: newProduct._id } },
{ upsert: true, new: true },
function(err, doc) {
console.log(err, doc);
}
);
The console.log prints out this:
{
//...
addedItems: [ 5ab0223118599214f4dd7803 ]
}
Everything looks good. I go to actually look at the data using the front-end website for my mongo db; I'm using mlab.com, and this is what shows:
{
//...
"addedItems": [
{
"$oid": "5ab0223118599214f4dd7803"
},
{
"$oid": "5ab0223118599214f4dd7803"
}
]
}
Question: What the heck happened? Why does it add an additional entry into addedItems ?! Even though my console.log only showed one.
Note:
I tested to see if the backend route was being called more than once. It is not.
It seems to be a problem with $push because if I just have { addedItems: newProduct._id } then only one entry goes in, but it overwrites the entire array.
Edit:
Made a test project to produce the same results: https://github.com/philliprognerud/test-mcve-stackoverflow
Can anyone figure out what's going on?
The problem is caused by your mixed used of promises (via async/await) and callbacks with the findOneAndUpdate call which ends up executing the command twice.
To fix the problem:
const updatedUser = await User.findOneAndUpdate(
{ id: userID },
{ $push: { addedItems: newProduct.id } },
{ upsert: true, new: true }
);
console.log(updatedUser);
Future readers note that the use of await isn't shown here in the question, but is in the MCVE.
I am facing similar issue. Just landed to this page. I find that previous answer is not very descriptive. So posting this:
export const updateUserHandler = async (req, res) => {
const request = req.body;
await User.findOneAndUpdate( //<== remove await
{ _id: request.id },
{ $push: { addedItems: newProduct._id } },
{ upsert: true, new: true },
(findErr, findRes) => {
if (findErr) {
res.status(500).send({
message: 'Failed: to update user',
IsSuccess: false,
result: findErr
});
} else {
res.status(200).send({
message: 'Success: to update user',
IsSuccess: true,
result: findRes
});
}
}
);
}
Here there are two async calls one is the async and other is await. Because of this there are two entries in the document. Just remove await from await User.findOneAndUpdate. It will work perfectly.
Thanks!!
When you await Query you are using the promise-like, specifically, .then() and .catch(() of Query. Passing a callback as well will result in the behavior you're describing.
If you await Query and .then() of Query simultaneously, would make the query execute twice
use:
await Model.findOneAndUpdate(query, doc, options)
OR
Model.findOneAndUpdate(query, doc, options, callback)
This code $push keeps adding two entries:
const ali={ "_id": "5eaa39a18e7719140e3f4430" };
// return await customerModel.findOneAndUpdate(
// ali,
// {
// "$push": {
// "address": [objAdr],
// },
// },
// function (error: any, success: any) {
// if (error) {
// console.log(error);
// } else {
// console.log(success);
// }
// }
// );
My solutions working true:
return await customerModel
.findOneAndUpdate(
{ _id: ids },
{ $push: { "address": objAdr } }
)
.catch((err: string | undefined) => new Error(err));
I'm trying to $push and $set at the same time, $push is working just fine, when it comes to $set, it generates this error:
MongoError: The positional operator did not find the match needed from
the query. Unexpanded update: files.$.name
Here's the code
Course.update(
{
_id: req.body.courseId,
'files.fileUrl': { $ne: url }
},{
$push: { files: { fileUrl: url } },
$set: {'files.$.name': file.name},
}, function(err, count) {
if (err) return next(err);
console.log("Successfully saved")
});
and the ORM model, I'm using mongoose
var CourseSchema = new Schema({
files: [{
fileUrl: String,
name: { type: String, default: 'File name'}
}]
});
Any help would be appreciated. Thanks.
As the error states looks like the query used is returning no documents or returning documents having no files[].
Another reason for which it might be throwing error is that you're trying to $push & $set in the same field files and probably running into an issue similar to https://jira.mongodb.org/browse/SERVER-1050
IMHO, there is no good reason to use the same field in $push & $set, instead you can simply change
$push: { files: { fileUrl: url } },
$set: {'files.$.name': file.name},
to
$push: { files: { fileUrl: url, name: file.name } },
I have written similar kind of query for my project
Hope u could relative this to your scenario
exports.candidateRating = function(req, res) {
console.log(req.query);
console.log(req.body.RoundWiseRatings);
Profiles.update({
"name": req.query.name
}, {
$set: {
"ratings": req.body.ratings,
},
$push: {
"RoundWiseRatings": req.body.RoundWiseRatings
}
}, {
multi: true
}, function(error, profiles) {
if (error) {
}
return Profiles.find({
name: req.query.name
}, function(err, profiless) {
console.log(profiless);
if (err) {
return handleError(res, err);
}
return res.status(200).json(fnStruncturedData(profiless[0].RoundWiseRatings));
});
});};
And this worked for me :)