Missing property at client side Nodejs - node.js

My simple problem is:
I had an mongoose object at server side:
...
item = {
name: "Test",
id: 1
}
// item was an mongo schema
// id and name was define in model String and Number
Then I add into item new field mentions:
item.mention = [{ id: 1, ... }]
But I can't get mention at client side.
My response code:
res,json({ status: 1, message: 'success', data: item })
The response was data: { name: "Test", id: 1 }
I don't want to add mention into my mongo schema.
So, what's my problem?
How can I fix that?
Thanks!

The problem is that item is a MongooseDocument, not a plain javascript object.
There are multiple ways to achieve what you want.
1) Using .lean()
Documents returned from queries with the lean option enabled are plain
javascript objects, not MongooseDocuments
Model.findOne().lean().exec((err, item) => {
item.mention = [{ id: 1 }];
res.json(item);
});
This option will increase the performance since you ignore the overhead of creating the Mongoose Document
2) Using: .set()
item.set('mention', [{ id: 1}], { strict: false });
4) Using spread operator
res.json({
status: 1,
message: 'success',
data: { mention: [{ id: 5 }], ...item }
})
4) Using Object.assign as #Alexis Facques explained.

Taking advantage of Object.assign() should resolve your problem too.
res.json({
status: 1,
message: 'success',
data: Object.assign({ mention: [{id: 1...}] },item)
})

Related

Mongoose: updateMany() is not working as expected

I'm using mongoose to handle my DB queries. I'm trying to update a set of records entirely using this method. Mode code looks like this:
// prepare database query
const filter = { type: 'company' };
const update = req.body.payload; // payload contains the array of objects (i.e. updated records)
const options = { new: true, runValidators: true }
// find and update the taxonomy record
await Taxonomy.updateMany(filter, update, options);
But whenever I run this query I'm getting following error in the console:
Error [MongooseError]: Invalid update pipeline operator: "_id"
I suppose there is something wrong in my update payload. The req.body.payload looks like this:
[
{
_id: '5ef3d08c745428001d92f896',
type: 'company',
name: 'Company Size',
__v: 0
},
{
_id: '5ef3cdc5745428001d92f893',
type: 'company',
name: 'Company Industry',
__v: 0
}
]
Can you please tell me what actually is wrong here?
This is not the right usage of updateMany() - it is aimed to update many documents with a single change.
To update many documents use bulkwrite() (docs) :
async function myUpdateMany(Model, objectsArray) {
try {
let ops = []
for (let obj of (objectsArray || [])) {
ops.push({
updateOne: {
filter: { platformId: obj.platformId },
update: obj,
upsert: false, // set "true" if you want to add a new document if it doesn't exist
}
})
}
Model.bulkWrite(ops, { ordered: false });
} catch (err) {
throw Error("myUpdateMany error: " + err)
}
}
Regarding runValidators, according to this, it seems to work by default.

Why am I getting the following Redis warning and error?

When I try to save the following data to Redis:
{ _id: 5c9535a742e1ce2b2ce90be5,
email: 'admin#admin.com',
items:
[ { _id: 5c9535c042e1ce2b2ce90be6, product: [Object], quantity: 1 },
{ _id: 5c9535c642e1ce2b2ce90beb, product: [Object], quantity: 1 } ],
createdOn: 2019-03-22T19:21:11.349Z,
__v: 0 }
I get the following warning:
node_redis: Deprecated: The SETEX command contains a argument of type model.
This is converted to "{ _id: 5c9535a742e1ce2b2ce90be5,
email: 'admin#admin.com',
items:
[ { _id: 5c9535c042e1ce2b2ce90be6, product: [Object], quantity: 1 },
{ _id: 5c9535c642e1ce2b2ce90beb, product: [Object], quantity: 1 } ],
createdOn: 2019-03-22T19:21:11.349Z,
__v: 0 }" by using .toString() now and will return an error from v.3.0 on.
Please handle this in your code to make sure everything works as you
intended it to.
When I try to retrieve the data from Redis, I get the following error:
undefined:1
{ _id: 5c9535a742e1ce2b2ce90be5,
^
SyntaxError: Unexpected token _ in JSON at position 2
at JSON.parse (<anonymous>)
Function used to save to Redis:
exports.setCart = (email, cart) => {
cart - JSON.stringify(cart);
redisClient.setex(email, CACHE_TTL, cart);
}
Function used to retrieve the data from Redis:
exports.getCart = (email, callback) => {
redisClient.get(email, (err, cart) => {
if(err) {return callback(err, null)}
console.log('CART FROM CACHE ', cart)
return callback(err, JSON.parse(cart));
})
}
Function call to save data to redis:
redisClient.setCart(email, cart);
I don't think redis is capable of handling JSON objects directly - especially nested JSONs. You can store a simple JSON object as a hash (by simple I mean that it is a flat JSON with no properties containing other nested JSON objects).
The simplest solution is to JSON.stringify() everything before storing them and then JSON.parse() them when you retrieve them.
This is fine if your objects are not too big however it is still not ideal. Another option is to use the flat npm package that basically flattens your nested JSONs so that they can be stored as hashes. You can see more info about it on this Medium article.
Sorry, folks, simple syntax error:
cart - JSON.stringify(cart);
Shoud be:
cart = JSON.stringify(cart);

Cannot retrieve field mongoose in client side

My simple problem is:
I had an mongoose object at server side:
...
item = {
name: "Test",
id: 1
}
// item was an mongo schema
// id and name was define in model String and Number
Then I add into item new field mentions:
item.mention = [{ id: 1, ... }]
But I can't get mention at client side.
My response code:
res.json({ status: 1, message: 'success', data: item })
The response was data: { name: "Test", id: 1 }
I don't want to add mention into my mongo schema.
So, what's my problem?
How can I fix that?
Thanks!
You can convert your mongoose document to an object first, then add your additional field.
Something like this:
let o = item.toObject();
o.mention = [{ id: 1, ... }];
res.json({ status: 1, message: 'success', data: o })
You could also just put this additional data in your response:
res.json({ status: 1, message: 'success', data: item, mention: [...] })
Try:
item = JSON.parse(JSON.stringify(item));
Before asign new prop for item.
Now you can asign value for new prop item.mention = some_value;
This will give you a new copy object that you can work with.
You cannot assign a new prop value to mongoose object which has not been defined before.

MongoDB not returning empty objects in document

I've got this JSON snippet in a much much larger MongoDB document:
formConfig: {
person: {},
title: {name: 'title', ... },
name: {name: 'name', ...}
}
However, when I then try to retrieve the document containing this JSON it doesn't return person: {} at all. All I'm getting is:
formConfig: {
title: {name: 'title', ... },
name: {name: 'name', ...}
}
Which completely breaks the frontend side of things since I need to know that person is there, regardless if it's empty or not.
When I search for this issue I can't find any similar questions or resources explaining why this happens in the first place, let alone how I can fix it.
So how do I fix it so it returns the person as well?
Here's the actual query, appConfig contains the JSON as mentioned:
exports.getSingle = (req, res, next) => {
AppConfig.findOne({_id: req.params.id})
.exec((err, appConfig) => {
res.json({
error: null,
data: appConfig
});
}
);
};
The issue was actually at Schema level, not using minimize: false in the Schema options cause empty objects to be removed.
This works:
new Schema ({...}, {minimize: false});

Mongoose and Bluebird saveAsync not actually saving

I am attempting to update an existing record in Mongo DB and although the "save" completes successfully, The record in the DB is not actually updated. Here's a before an after of the data:
Before:
{
_id: '56be4ba9938e836b6f47e84a',
type: 'ec-input',
key: 'ec-input_2',
templateOptions: {
placeholder: 'My Placeholder...',
subtext: 'My Subtest',
label: 'My Label'
},
order: 1,
form: '56bd3e76413de7c862979b8c',
__v: 0
}
After:
{
_id: '56be4ba9938e836b6f47e84a',
type: 'ec-input',
key: 'ec-input_2',
templateOptions: {
placeholder: 'I am different now!!',
subtext: 'Me too..',
label: 'My Label'
},
order: 1,
form: '56bd3e76413de7c862979b8c',
__v: 0
}
The templateOptions field is configured as type mongoose.Schema.Types.Mixed on the mongoose model. Here's how i'm trying to save the update:
export function update(req, res) {
if (req.body._id) {
delete req.body._id;
}
Field.findByIdAsync(req.params.id)
.then(entity => {
var updated = _.merge(entity, req.body);
updated.saveAsync()
.spread(updated => {
if (entity) {
res.status(200).json(entity);
}
});
});
}
I set a breakpoint before updated.saveAsync is called and updated correctly has the modified data. I also set a breakpoint in the spread callback, and updated still has the modified data. After updated.saveAsync is complete, I check mongo directly, and the record was not updated.
Any ideas about what I can do to make this work would be greatly appreciated. Thanks!

Resources