WaterlineJs find() with no criteria and fields/select provided does not work - sails.js

I am trying to fetch all the records but with selected fields, I have tried the following ways but none works:
Post.find(
{
where: {},
select: ['title']
}
);
Post.find(
{},
{
fields: {
title: 1
}
}
);

As this answer points out, the fields param "WILL work as long as you pass other params with it such as limit or order."
Alternatively, if you want this throughout your application, you could define a custom toJSON function for your model, under attributes. If not, you could still define it under some other (e.g. filter) and use map to return the custom objects instead of the default model. Remember to take care of the control flow while using map though. Use async/promises/raw logic to avoid returning before all objects are processed.

The issue has been resolved in sails-mongo latest version:
https://github.com/balderdashy/waterline/issues/1098
Thanks

I've played with trying to get above answer to use limit or order to kick in the projection to no avail.
I did see this in the docs located here:
http://sailsjs.org/documentation/reference/waterline-orm/models/native
With an out of the box solution for exactly what you're doing (pasted here for ease of use).
Pet.native(function(err, collection) {
if (err) return res.serverError(err);
collection.find({}, {
name: true
}).toArray(function (err, results) {
if (err) return res.serverError(err);
return res.ok(results);
});
});
Swap out the response base things and change Pet to Post and, this ought to work in the sails console:
Post.native(function(err, collection) {
if (err) throw new Error(err);
collection.find({}, {
title: true
}).toArray(function (err, results) {
if (err) throw new Error(err);
console.log(results);
});
});
You'll still get the _id field, and if you don't want that then hit the Mongo docs on not getting those hint(title: true, _id: false)hint
Hope this helps!

Related

text index required for $text query in the MongoDB with Express

I built a Express back-end which is connected to local MongoDB
when I create a post to find out the specific term, it returns the error like this
MongoError: text index required for $text query
How can I fix this error?
this is my Express code
app.post("/api/search",(req,res)=> {
const term = req.body.searchTerm;
console.log(term); // Here I can check the request coming well
MongoClient.connect(url,(err,db)=> {
if(err) throw err;
const dbo = db.db("Exercise");
dbo.collection("exercise")
.find({$text:{$search:term}})
.toArray((error, result) => {
if (error) {
console.log(error);
return;
} else {
console.log("Success");
res.send(result);
}
});
});
});
Thank you in advance!
What you can do to solve your problem is simple. You can create a "text" on the field that you want search in you collection like this:
db.reviews.createIndex( { comments: "text" } )
Note: assumes "comments" is the field as seen in the docs
However, for the best results you might want to create a dynamic default Search index in MongoDB Atlas. It's free and easy. Because it is a dynamic default, you do not need to do any configuration. The results and performance will likely be better if you are powering a search experience.
I hope this info helps.

mongoose query return empty array if filter has a field name that is camel cased

The following issue was with some code written in express/nodejs.
I experienced something I could not find any material in regards,
I encountered an issue whereas making a find query with mongoose returned an empty array.
After tinkering I discovered it was due to the key used (customerRef) being camel cased
I tried to tweak other fields from and to camelcase and got the same issue.
see example here:
const lastCart = await Cart.findOne({ customerRef: customer._id }, function(err, docs) {
if (err) {
console.log('TCL: err', err);
}
console.log('TCL: docs', docs); //result = []
});
then went and tweaked my database objects from:
{
....
"customerRef" : "5dfcd194ca19972b888d66c2",
....
}
to:
{
....
"customerref" : "5dfcd194ca19972b888d66c2",
....
}
then the query worked as expected:(customerRef >>> customerref)
const lastCart = await Cart.findOne({ customerref: customer._id }, function(err, docs) {
if (err) {
console.log('TCL: err', err);
}
console.log('TCL: docs', docs); //result is now ok = [...]
});
Now to top this off here's another bit of info:
I use studio 3T for mMongoDB and over there I do not have this issue when making queries.
I would appreciate any and all explanation on this behavior aswell as alternatives if possible.
See my full repo here:
(My skills are novice at best so I apologize in advanced and welcome any feedback)
https://github.com/Darkmift/MEAN-SuperMarket/blob/master/backend/app/controllers/userController.js#L121
So after some time I have concluded the issue was with my use of the mongo shell program (Studio 3t)
at the time I was not aware how to properly insert an ObjectId.
When using the built in query one must add:
{
...
"customerRef" : ObjectId(RefId)
...
}
and NOT:
{
...
"customerRef" : "RefId"
...
}

MongoDb/Mongoskin - CLEANLY Update entire document w/o specifying properties

All the examples I have seen for MongoDb & Mongoskin for update, have individual properties being updated, like so:
// this works when I specify the properties
db.collection('User').update({_id: mongoskin.helper.toObjectID(user._id)},
{'$set':{displayName:user.displayName}}, function(err, result) {
if (err) throw err;
if (result){ res.send(result)}
});
But what if I wanted the whole object/document to be updated instead:
// this does not appear to work
db.collection('User').update({_id: mongoskin.helper.toObjectID(user._id)}, {'$set':user},
function(err, result){
// do something
}
It returns the error:
// It appears Mongo does not like the _id as part of the update
MongoError: After applying the update to the document {_id: ObjectId('.....
To overcome this issue, this is what I had to do to make things work:
function (req, res) {
var userId = req.body.user._id
var user = req.body.user;
delete user._id;
db.collection('User').update({_id: mongoskin.helper.toObjectID(userId)},
{'$set':user}, function(err, result) {
if (err) throw err;
console.log('result: ' + result)
if (result){ res.send(result)}
});
})
It there a more elegant way of updating the whole document, instead of hacking it with:
delete user._id
If you want to update the whole object, you do not need a $set. I am not aware of mongoskin, but in shell you would do something like:
var userObj = {
_id: <something>
...
};
db.user.update({_id: user._id}, user);
Which I think can be translated in your mongoskin in the following way.
db.collection('User').update({_id: user._id}, user, function(){...})
But here is the problem. You can not update _id of the element in Mongo. And this is what your error tells you. So you can remove the _id from your user object and have it separately. Search by this separate _id and update with a user object without _id.

Is there a way to query MongoDB Rest API with a list or array of IDs

I'm using a MEAN stack and with Mongoose. Is there a way to query MongoDB with multiple ids to only return those specific IDs in one query e.g. /api/products/5001,5002,5003
Is this possible or would I need to query each product individually or add an additional attribute to the products and query by that.
Update: To clarify as suggested below I've managed to get it partially working using {'_id': { $in: [5001,5002,5003]} however I'm having problems figuring out how to pass the list from the api url to the find function.
Using Express.js for router
router.get('/list/:ids', controller.showByIDs);
exports.showByIDs = function(req, res) {
Product.find({'_id': { $in: [req.params.ids]}}, function (err, product) {
if(err) { return handleError(res, err); }
if(!product) { return res.send(404); }
return res.json(product);
})
};
Then trying /api/products/list/5001 works however /api/products/list/5001,5002 doesn't. I'm not sure if it's a syntax problem in the url or my router code that needs to change or the controller.
You can use the $in operator to query for multiple values at once:
Products.find({_id: {$in: [5001, 5002, 5003]}}, function (err, products) { ... });
On the Express side, you need to use a format for the ids parameter that lets you split it into an array of id values, like you had in your first example:
/api/products/5001,5002,5003
Then in your route handler, you can call the split function on the req.params.ids string to turn it into an array of id values that you can use with $in:
exports.showByIDs = function(req, res) {
var ids = req.params.ids.split(',');
Product.find({'_id': { $in: ids}}, function (err, product) {
if(err) { return handleError(res, err); }
if(!product) { return res.send(404); }
return res.json(product);
})
};

Mongoose Aggregate: Empty results never trigger the callback

I am working with mongoose and defined some aggregations in the mongoshell.
Sometimes the match criteria filters out all data. Nevertheless: Mongoose does not call a callback.
This was very easy reproducable,e.g.
Contract.aggregate( {
$match:{user:'dummydata'}},
function (err, result) {
console.log('this never happens');
});
If I put in a existing user id, the callback gets called.
If I use a non existend user id, the callback just is never called.
But how should I know what happend?
Just by accident I found out, that there is the need for a second "no results" callback.
So the right solution is:
Contract.aggregate( {
$match:{user:'dummydata'}
},
function (err, result) {
console.log('this never happens');
},
function(err,result) {
console.log('Crap there is no result');
});