Mongoose: Array of objects not saving - node.js

I'm trying to add object id to array in mongoose (Node.js). Here is my code:
app.post('/api/users/:userId/favorites/:objectId', function(req, res, next) {
User.findByIdAndUpdate(req.params.userId, {$addToSet: {user_favorites: req.params.objectId}}, {safe: true, upsert: true}, function(err, data){
if (err) return res.status(500).send(err)
res.status(200).send({'message':'saved'});
})
})
And here is my model:
module.exports = mongoose.model('User',{
...
user_favorites: [{ type: mongoose.Types.ObjectId, ref: 'Property' }],
...
})
No errors are returned but the id is not added to the array. What am I missing?

You forgot the "new" option. The .find**Update() methods have this turned off by default, which is the same behavior as the root method .findAndModfiy():
User.findByIdAndUpdate(
req.params.userId,
{ "$addToSet": {
"user_favorites": req.params.objectId
},
{ "upsert": true, "new": true },
function(err, data){
if (err) return res.status(500).send(err)
res.status(200).send({'message':'saved'});
}
)
So the document is actually updated in the database, but without "new" then you get the original document found, and not the modified one.
Also, whatever tutorial you learnt from, the "safe" option has been deprecated for a very long time. All write concern setting default to acknowleded, which is what that setting is supposed to represent.

Related

Expected 'property' to be of type string, instead found type object - Dynamoose

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);
}
});

MongoError: The positional operator did not find the match needed from the query. at Function.create()

I am trying to update values into an object array(users) if it does not already exist in MongoDB. Here is my Schema:
ownerid:{
type: Number,
required: 'This field is required'
},
name:{
type: String
},
capacity:{
type: Number
},
basePrice:{
type: Number
},
users:[{
id: Number,
price: Number,
target: Number,
frequency: Number
}],
filePath:{
type: String
},
status:{
type: String
}
});
The following is my router method:
app.post('/userBid',urlEncodedParser,function(req,res){
resName=req.body.resName;
console.log(resName);
Resource.find({"name":resName},{"users.id": userid},function(err,existingUser){
if (!existingUser){
console.log("already in queue");
//res.render('userHome.ejs');
}
else{
console.log("in update");
Resource.update({'name': resName},
{'$set': {
'users.$.frequency': 1,
'users.$.id': userid,
'users.$.price': req.body.price,
'users.$.target': req.body.target
}},{'multi': true},
function(err,model) {
if(err){
console.log(err);
return res.send(err);
}
return res.json(model);
});
}
});
});
I have tried using $push but that does not seem to work either. Also I can't use '0' instead of '$' as multiple users will be inserted by the users and I need to store them all.
Issue :
Reason why we use $ is to update a specific object/few specific objects in an array field that meet our condition. So when you use any positional operators like $ or $[] then in filter part of .update({filterPart},{updatePart}) query you need to use a filter to find specific object in array. So for example if id field is unique in users array then you can use it to filter/find the object needs to be updated.
Try this below code :
app.post("/userBid", urlEncodedParser, function (req, res) {
resName = req.body.resName;
console.log(resName);
/** Use findOne if `name` is unique.
* Cause `existingUser` will be array, instead findOne will return an object or null - So you can just do if(existingUser)to check true values */
Resource.find({ name: resName }, { "users.id": userid }, function (
err,
existingUser
) {
if (!existingUser) {
console.log("already in queue");
//res.render('userHome.ejs');
} else {
console.log("in update");
Resource.update(
{ name: resName, "users.id": userid }, /** `"users.id": userid` is the only change needed */
{
$set: {
"users.$.frequency": 1,
"users.$.id": userid,
"users.$.price": req.body.price,
"users.$.target": req.body.target,
},
},
{ multi: true },
function (err, model) {
if (err) {
console.log(err);
return res.send(err);
}
return res.json(model);
}
);
}
});
});

Mongoose update returns undefined

How can I update a field with new properties that is initially set to be an empty object?
For example, I have the following schema:
import mongoose from 'mongoose';
var RunSchema = mongoose.Schema(
{
runId: { type: String },
reports: {
cookieSummary: {
name: String,
path: String
}
}
}
)
export default mongoose.model('Run', RunSchema);
And I'm trying to update the following document:
{
"_id": {
"$oid": "5a0565c2537e0b5d9d08ee6b"
},
"__v": 0,
"reports": {},
"runId": "8r4LNN3fRqd3qNgdW"
}
But when I run this code, it returns undefined:
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {'reports.cookieSummary': { 'name': 'test' }},
}, (err, doc) => { console.log(doc) })
The object notation works after adding type to fields, like this: name: { type: String }
Try to use dot notation, as you're setting just one field:
Run.findOneAndUpdate(
{ runId: '8r4LNN3fRqd3qNgdW' },
{ $set: {'reports.cookieSummary.name': 'test' } },
(err, doc) => { console.log(doc) })
According to the docs, the command you're using should work but you write it wrongly. Try like this:
Run.findOneAndUpdate(
{ runId: '8r4LNN3fRqd3qNgdW' },
{ $set: { 'reports.cookieSummary': {'name': 'test'} } },
(err, doc) => { console.log(doc) })
if it does not work, maybe mongo expect that the object matches its schema when you use the command like this. But I don't think so.
Let me know.
Your query for update a document is good only the mistake is at the end of curly braces of $set. You entered un-necessary comma at the end that is actually creating problem in this case. So I suggest you to remove it and run this :
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {'reports.cookieSummary': { 'name': 'test' }}
}, (err, doc) => { console.log(doc) });
and then see. Rest of your query is fine.
Hope It will work for you.
Thanks.
Try using below code, it will update the document and return the updated document.
var Q = require('q');
var deferred = Q.defer();
Run.findOneAndUpdate({ runId: '8r4LNN3fRqd3qNgdW' }, { $set: { 'reports.cookieSummary.name': 'test' } }, { new: true },
(err, doc) => {
console.log(doc);
deferred.resolve(doc);
});
return deferred.promise;
I made a small change. Test this solution.
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {"reports": {'cookieSummary':{'name': 'test'}}},
}, (err, doc) => { console.log(doc) })

How to send a updated values in nodejs?

I need to send all urls including last updated values from mongodb.
but i only get previous updated values.Can any body tell the me solution .
new_add_schema.findOneAndUpdate(
{
user_id: req.body.user_id
},
{
$push:
{
filename:
{
url:img_filename
}
}
},
function(err, doc) {
console.log(doc)
});
In mongoose you can pass options as the third argument for this method. If you pass new: true in options then Mongo will return the updated document. It is false by default.
So query like this -
new_add_schema.findOneAndUpdate(
{
user_id: req.body.user_id
},
{
$push:
{
filename:
{
url:img_filename
}
}
},
{new: true}, // notice this options argument
function(err, doc) {
console.log(doc)
});
You can see the documentation here.

How do i $set and $push in one update MongoDB?

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 :)

Resources