Why am I getting the following Redis warning and error? - node.js

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

Related

Cannot read property 'columnName' of undefined in sails Js Mongo DB

I am using sails JS with Mongo DB.
My model is:
module.exports = {
attributes: {
title:{type:"string",required:true},
content:{type:"string",required:true},
date:{type:"string",required:true},
filename:{type:"string",required:true},
},
};
My Controller is:
fetchposts:function(req,res){
console.log("in fetch posts")
mysort={$id:-1}
Cyberblog.find().sort(mysort).limit(5).exec(function(err, result) {
if (err || !result) {
message="no records fetched";
console.log(message);
res.redirect('/newpost');
}
else{
console.log(result)
}
I am facing an error saying that
"Warning: The sort clause in the provided criteria is specified as a dictionary (plain JS object),
meaning that it is presumably using Mongo-Esque semantics (something like { fullName: -1, rank: 1 }).
But as of Sails v1/Waterline 0.13, this is no longer the recommended usage. Instead, please use either
a string like 'fullName DESC', or an array-like [ { fullName: 'DESC' } ].
(Since I get what you mean, tolerating & remapping this usage for now...)
and I am unable to fetch any records. It is showing no records fetched.
So I have one warning on Sort and no records coming from DB. Please help me resolve the issue.
Sort clause allow send string:
var users = await User.find({ name: 'Jake'})
.sort('age ASC');
return res.json(users);
Or an array:
var users = await User.find({ name: 'Finn'})
.sort([
{ age: 'ASC' },
{ createdAt: 'ASC' },
]);
return res.json(users);
Check this out in the documentation:
https://sailsjs.com/documentation/reference/waterline-orm/queries/sort

findByIdAndUpdate does not work in express, but does work in mongo tool [duplicate]

This question already has answers here:
Mongoose: findOneAndUpdate doesn't return updated document
(16 answers)
How to push an array of objects into an array in mongoose with one call?
(4 answers)
Push to two separate arrays in one update call in mongodb
(1 answer)
Closed 4 years ago.
I am a beginner of mongodb and express, now I am trying to update some data. I do not think there is something wrong in my code, when I turn debugging on, the following db operation is printed out and does not return any error from catch, therefore without any doubt, I thought the following update is executed without fail. Even I tested with the following update statement directly from mongo client tool, it worked fine. However it is not reflected on the actual database if I update from express. If updating is not successful, it should return some error, but it does not. Could you anyone give me some advice for this? I really do not know what is happening here, the following db operation works well from the mongo client tool. From express, it does not return error also. So, I come to ask about this.
Mongoose: persons.findOneAndUpdate({ _id: ObjectId("5be6d1087594078eac687f19") }, { '$push': { hobbies: { '$each': [ 'TEST', 'SING', 'SWIM' ] } } }, { '$push': { skills: [ 'programming' ] }, upsert: false, projection: {}, returnOriginal: true })
router.post("/edit/:id", (req, res, next) => {
var hobbies = req.body.hobbies.split(",");
var skills = req.body.skills.split(",");
Person.findByIdAndUpdate(
req.params.id,
// { $set: { name: req.body.name } }
{ $push: { hobbies: hobbies} },
{ $push: { skills: skills} }
)
.exec()
.then(person=> {
res.json(person);
})
.catch(err => {
console.log("ERROR", err);
});
});

Missing property at client side Nodejs

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

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

TypeError: Object.keys called on non-object when updating document

I'm trying to update an existing document by increment a counter and pushing an object to an array.
Here's the schema for User:
var UserSchema = new Schema({
[...]
posts: {
totalWords: { type: Number, min: 0, default: 0 },
_entries: [
{
words: { type: Number, min: 0 },
body: { type: String },
date: Date
}
]
},
});
And here's the update code:
var newPost = {
words: req.body.words,
body: req.body.entry,
date: new Date()
};
User.findOne(req.user._id, function (err, user) {
var previous = user.posts.totalWords;
user.posts.totalWords = previous + newPost.words;
user.posts._entries.push(newPost);
user.save(function (err) {
if (err) return res.send(400, err);
return res.json(newPost);
});
});
I get the following error:
[TypeError: Object.keys called on non-object]
Any ideas on how to solve this?
Answering my own question
I was able to solve the problem by changing:
User.findOne(req.user._id, function (err, user) { [...] });
Into this:
User.findById(req.user._id, function (err, user) { [...] });
I think, if you would like to use findOne you need follow syntax:
User.findOne({'_id': req.user._id}, {}, function (err, user) {
...
});
Not sure about findById() vs. findOne(), but I've had problems with Mongoose objects returning Object.keys called on non-object while saving or updating with mal-formed data or data corresponding to an older schema. While initializing the document, Mongoose was expecting a subdocument of some kind, but the data in the database didn't match that.
For me it usually happens when I change schemas from a simple object (String, Number, etc.) to a more complex subdocument of some kind. The schema types are mixed up and the object won't load, not even to fix the problem. I had to go into my database using the native driver, search for mal-formed documents using the $type operator, and update them individually.

Resources