Sorting in mongoose Express does not sort properly - reactjs

I need help with sorting in Express working with mongooose db.
When i use sort({'price':1}) everythink is good, but when i pass JSON.stringify(sort) which contains and logs out {"price":1} it stops working. Any ideas why?
if(req.query.sortOption){
const str = req.query.sortOption.split(':');
sort[str[0]] = str[1] === 'desc' ? -1:1;
}
console.log(JSON.stringify(sort));
//here logs out {"price":-1} which works when i pass it into sort function as a string
try {
const annoucements = await Annoucement.find(query)
.skip(page * annoucementsPerPage)
.limit(annoucementsPerPage)
.populate('author')
.sort(JSON.stringify(sort))
res.status(200).json({
status: 'Successfully got an annoucement',
results: annoucements.length,
data: {
annoucements,
},
});
} catch (error) {
res.status(500).json({
status: 'Failed to get all annoucements',
message: error,
});
}
};

How to sort in mongoose?
.sort() takes in an object, and does not take in a string. You used JSON.stringify(sort), which made the sort query into a string, hence mongoose could not parse it.

Solution:
You should just pass .sort(sort) instead of transforming the object to a string.
Explanation:
Mongoose either accepts
a string like "price" (for ascending order) or "-price" (for descending order).
an array (not applicable in this case)
an object, where the key is the property name and the value is the order (1, "asc", "ascending" or -1, '"desc", "descending"`)
What you did was basically pass the string value "{price:-1}" to it, which does not match any of the use cases. Therefore your sorting does not work as expected.

Related

How to check an array with regular expression in GraphQL

I need to check the existence of some elements in an array as such
I have an array as such
ar = ['one','two','three']
I want to know how I can individually check the elements in the regular expression code below instead of "/something/" that would map through my array and check if they exist in graphQL one by one.
similar : allCockpitHello (filter: {Association : {value : {regex: "\/something/" }}} limit:2){
nodes{
Name{
value
}
}
You need to have the regex string as an input parameter to be used by the resolver, GraphQL is not going to do the filter for you, you need to do/call that logic in the resolver based on your inputs.
Based on your example, you could have something like this on the schema and resolver:
type Node {
name: String!
}
type NodeQueries {
nodes (filterRegEx :String): [Node]!
}
Once you have the input string on the resolver, the implementation of the filter mechanism is up to you.
const resolvers = {
...
NodeQueries: {
nodes: (parent, params) => {
const {filterRegEx} = params; // regex input string
const ar = ['one','two','three'];
// Create a RegExp based on the input,
// Compare the with the elements in ar and store the result...
// You might end up with ... res = ['one', 'three'];
// Now map the result to match your schema:
return _.map(res, name => ({name}) ); // to end up with [{name: 'one'}, {name: 'three'}]
}
}
...
}
GraphQL is not a magic bullet - it's only a query language, it 'transports' your needs to the engine (local client, remote server ...) where all the necessary processing takes place.
In this case you probably need to pass your array and expression as variables to the server (resolver). If processing is expensive results (similar relation) should be already defined, cached, preprocessed, etc.
If dataset is small you can do this entirely client-side - iterate over an array (fetched using graphql).

Mongoose querying the array... changing the elements of the array

I am trying to remove all the elements from the array in the MongoDB database, then I insert all the new array elements.
My Model is:
const mongoose = require('mongoose');
var schema = new mongoose.Schema({
email : {
type : String
},
password : {
type : String
},
stocks : {
type : [String]
}
}, {versionKey:false}, {_id: false});
module.exports = final = mongoose.model('users', schema);
My stocks array will then have some values. I am trying to remove those values using the following command:
I read at somewhere in Stack Overflow that to empty your array you can do many things but a set is the fastest way to do this. Please let me know if you know any other way which is better than this.
final
.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:[]}})
.then(()=>console.log("Data removed."))
.catch(err=>console.log(err));
Once data is removed it means the array will get emptied. Then I assign the whole set of the new array from my local variable like this:
const newData = {
stocks : ["abcd", "wxyz"]
};
Now I am trying to assign this new array to my database using this command:
final
.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:newData.stocks}});
It is emptying the array successfully, but when I am assigning new array it is not working and shows an empty array. Can anyone assist me with this, please?
Try with
final.findOneAndUpdate({email:"abcd#gmail.com"}, {$set:{stocks:newData.stocks}}, {new: true})
.then((doc)=>console.log(doc))
.catch(err=>console.log(err));
If you don't use a callback the query is not executed.
The query executes if callback is passed else a Query object is returned.
Mongoose documentation

Mongoose Model, cleaning/parsing an Array efficiently

I am having some issues with a mongoose array, it's likely due to my lacking understanding of the library, and I can't find the exact answer I'm looking for in the docs.
For starters I have my schema and model declarations:
const gConfig = new Schema({ aList: Array, maxChanLimit: Number }), globalConfiguration = mongoose.model('globalConfig', gConfig);
And I have my command which fetches the array, parses out _id, then pushes the new item to the array, and overwrites the existing one in the database.
if((message.author.id === g.ownerID) && (g.id.toString() === tocGuild) && message.content.startsWith("!updatealist"))
{
let mc = message.content.replace("!updatealist ", "");
globalConfiguration.findOneAndUpdate({},{$push: {"aList":mc }}, { upsert: true }, function(err, data) {
if (err) return console.log(err);
var str = JSON.stringify(data); str = str.replace(RegExp(/"_id"|"__v"|'/g),""); var arr = str.split(`","`);
});
}
I feel like there has to be a better way to do this, I've tried something like this based on what I've read:
globalConfiguration.findOneAndUpdate({},{$push: {"-_id aList":mc }}
However this did not remove _id from the array. I suppose how I'm doing it is a way to do it, but I know it isn't efficient, and isn't dynamic at all, it's also extremely bulky in terms of code and could be streamlined using the library.
In practice, what is the best way to properly read an array from a model with Mongoose? How do you read from the array without the additional objects Mongoose adds by default? What is the best way to add an item to an existing model?
Any help is appreciated, thank you.
if you want to have more control over the updating process, you can do it like this, in the mongoose documents it suggest you can first query the item/document you want to update, once that document is queried and there, you can make changes to it such as if it contains an array , you can push to it or pop from it or what ever..
its in your control
so,
if((message.author.id === g.ownerID) && (g.id.toString() === tocGuild) && message.content.startsWith("!updatealist"))
{
let mc = message.content.replace("!updatealist ", "");
globalConfiguration.findOne({"your query"}, function(err, data) {
if (err) throw (err);
data.array.push("something");
data.save();// save it again with updates
var str = JSON.stringify(data); str = str.replace(RegExp(/"_id"|"__v"|'/g),""); var arr = str.split(`","`);
});
}

Sequelize doesn't return anything if value for $notIn is an empty array but it returns me if array contains an empty value

I want Sequelize to return to me all the values which IDs are not in an array.
Sequelize doesn't return anything if value for $notIn is an empty array but it returns me if array contains an empty value.
This returns me nothing:
db.foo.findAll({
where: {
id: {
$notIn: []
}
}
});
This returns me every value:
db.foo.findAll({
where: {
id: {
$notIn: ['']
}
}
});
How come it doesn't return all values if the array is empty? If it is empty, then it means all values which values are not in that array should be returned. Since the ID doesn't contain any value, sequelize should return to me all the values, right?
This issue will be fixed in Sequelize version 4. That version has not been fully disclosed yet, though. At least there is no documentation yet.
See the GitHub issue at https://github.com/sequelize/sequelize/issues/4859.
The changelog can be found at https://github.com/sequelize/sequelize/blob/master/changelog.md. It says
[FIXED] $notIn: [] is now converted to NOT IN (NULL) #4859
Maybe you can implement those version 4 changes in your current code yourself.
For those using < 4 version, here is a work around I used,
let idsToSkip = [...]; //generate array of ids, this may result in empty array
idsToSkip.push('-1'); // push a value that can not be the id in table. this will generate `not in ('-1')` query serving the purpose.
db.foo.findAll({
where: {
id: {
$notIn: idsToSkip
}
}
});
Hope it helps !!

Sending array to populate geospatial field using Mongoose + NodeJS

I'm trying to save a geospatial array into a Schema. Here is my Schema (I'm using Moongose + Express + NodeJS):
var Route = new schema({
route: String,
time: Number,
distance: Number,
geo: {type: [Number], index: '2d'},
created: { type: Date, default: Date.now }
}, {collection: 'route'});
var routeModel = mongoose.model('Route', Route);
And here is an example of the data I'm sending to populate an instance of that schema:
{
distance: 6.899893863658173,
geo:[ [13.695901, -89.24937], [13.706500876975248, -89.24967010761316],
[13.711430396814366, -89.2561502488519] ],
route: "Running route",
time: 31
}
First noob question is: is it possible to do what I'm doing? sending an array of arrays in geo?
And here is how I save the data:
socket.on('new_route', function (data){
var route = new routeModel();
route.route = data.route;
route.time = data.time;
route.distance = data.distance;
route.geo = data.geo;
route.save(function(err) {
if (err) throw err;
socket.emit("route_saved", {mensaje: "Well done!"});
app.listen(8080);
});
});
If I send and empty array on geo, all works fine. However, I'm getting the following error
"Cast to number failed for "13.695901, -89.24937, 13.706500876975248, -89.24967010761316..." at path "geo".
whenever I send an array (like the one posted above) on "geo".
So second question, any ideas on why I'm getting my array threated like a big string?
Mongoose doesn't support arrays of arrays of any type ([[Number]]). It may be supported in the future.
If your use case requires this schema, use a Mixed type which allows ad-hoc structures but provides no change tracking or casting.
new Schema({ geo: { type: Schema.Types.Mixed, index: '2d' }})
As for arrays being treated as a big string, mongoose converts the invalid argument to a string and what you observe is an artifact of how javascript converts arrays to strings.
var a = [3,4,5]
console.log(String(a)) // '3,4,5'

Resources