Define getting property on query using SailsJS model - node.js

I want to query a library by id, and I need only some properties. I tried below script but it is not working:
Library.findOne({
id: libraryId
}, {
latitude: 1, longitude: 1,
name: 1, address: 1, image: 1
}).exec(function (err, libObj) {
if (err)
return res.ok(err);
return res.ok(libObj);
});
What is wrong in my code?

For projections you could use the native() method that has direct access to the mongo driver:
var criteria = { id: libraryId },
projection = { latitude: 1, longitude: 1, name: 1, address: 1, image: 1 };
// Grab an instance of the mongo-driver
Library.native(function(err, collection) {
if (err) return res.serverError(err);
// Execute any query that works with the mongo js driver
collection.findOne(criteria, projection).exec(function (err, libObj) {
console.log(libObj);
});
});
-- UPDATE --
Another option is to use the find() method which can accept the criteria and projection documents as parameters and append limit(1) to return just one document. For the projection object you would need to use the select key that holds an array of the projection fields:
var criteria = { _id: Library.mongo.objectId(libraryId) },
projection = { select: [ "latitude", "longitude", "name", "address", "image" ] };
Library.find(criteria, projection).limit(1).exec(function (err, res) {
var libObj = res[0];
console.log(libObj );
});

#chridam Thanks a lot for your answer. I changed something and the script working well
var criteria = { _id: Library.mongo.objectId(libraryId) },
projection = { latitude: 1, longitude: 1, name: 1, address: 1, image: 1 };
// Grab an instance of the mongo-driver
Library.native(function(err, collection) {
if (err) return res.serverError(err);
// Execute any query that works with the mongo js driver
collection.findOne(criteria, projection, function (err, libObj) {
sails.log(libObj);
sails.log(err);
});
});

Related

Filter in pre (find) hook Mongoose

I'm trying to perform a query that filters an array from another document, to mention something about the structure, I try to populate the document based on the specified product and store id, so that it doesn't bring the other data from the array but in this case I understand that I can't access the document fields while in the middleware, I'm reading the documentation but I still learning concepts
bUnitSchema.pre(/^find/, function (next) {
this.populate({
path: "menuItem.product",
select: {
"storeId.$": 1,
},
match: {
"storeId.store": "62a811d1af67f5415770f297",
},
});
next();
});
any guide would be of excellent help
I try something like this
bUnitSchema.pre(/^find/, function (next) {
this.populate({
path: "menuItem.product",
select: {
"storeId.$": 1,
},
match: {
*//here im trying to do something like this*
*"storeid.store": bUnitSchema.menuItem.store*
},
});
next();
});
but give me
store not defined
I can solve it, i use a post hook :
bUnitSchema.post(/^find/, async function (docs) {
for (let doc of docs) {
for (let store of doc.menuItem) {
await doc.populate({
path: "menuItem.product",
select: {
image: 1,
imagePath: 1,
plateFor: 1,
description: 1,
name: 1,
_id: 1,
"storeId.$": 1,
},
match: {
"storeId.store": store.store,
},
});
}
}
});
If anyone has a better idea, it would be appreciated.

How to push data into existing element of the array of objects in nodejs?

I have this array list of objects.
var list = [{
'ID':1,
'name' : 'Vikas Yadav',
'mobile':8095638475,
'sent':false
},
{
'ID':2,
'name' : 'Rajat Shukla',
'mobile':7486903546,
'sent':false
},
{
'ID':3,
'name' : 'Munna Bhaiya',
'mobile':9056284550,
'sent':false
},
{
'ID':4,
'name' : 'Guddu Pandit',
'mobile':7780543209,
'sent':false
},
{
'ID':5,
'name' : 'Srivani Iyer',
'mobile':8880976501,
'sent':false
}];
Now I want to push two more datas in specific element of this array via forLoop as:
var timeAndOTPArray = {
"time" : new Date(),
"OTP": req.params.ran
}
I am retrieving the list data via cookies into one of the route.
Below is the code I am trying to push the element according to the matching condition.
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with name
(lists[item]).push(timeAndOTPArray);
newAddedList.push(lists[item]);
console.log(item, lists[item]);
}
});
Perhaps it's not the correct way. Please help!
Wish you a happy and a prosperous Diwali.
Cheers!
You can use findIndex and append to update the object into list like this:
//List only with ID, easier to read the code
var list = [{'ID':1,},{'ID':2,}]
//your object
var timeAndOTPArray = {
"time" : new Date(),
"OTP": "otp"
}
//Index where object with ID == 2 is
var index = list.findIndex(obj => obj.ID == 2);
//Append the 'timeAndOTPArray' properties into the object itself
list[index] = {"time": timeAndOTPArray.time, "OTP":timeAndOTPArray.OTP, ...list[index]}
console.log(list)
I guess this will help
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with ID
Object.keys(timeAndOTPArray).forEach(key=>{
lists[item][key]=timeAndOTPArray[key];
})
}
});
Good evening) I can advice you the best option is update with map
const listItems = [
{
ID: 1,
name: 'Vikas Yadav',
mobile: 8095638475,
sent: false,
},
{
ID: 2,
name: 'Rajat Shukla',
mobile: 7486903546,
sent: false,
},
{
ID: 3,
name: 'Munna Bhaiya',
mobile: 9056284550,
sent: false,
},
{
ID: 4,
name: 'Guddu Pandit',
mobile: 7780543209,
sent: false,
},
{
ID: 5,
name: 'Srivani Iyer',
mobile: 8880976501,
sent: false,
},
];
const paramId = 4;
const result = listItems.map((item) => {
if (paramId === item.ID) {
return {
...item,
time: new Date(),
OTP: 'smth',
};
}
return item;
});
console.log('result', result);
for appending, you can do this,
lists[index] = Object.assign(lists[index], timeAndOTPArray);
If you are using es6,
lists[index] = {...lists[index], timeAndOTPArray};
Here lists is an array of objects.
so lists[item] is an object, so you cant push an object to an object.
In your code timeAndOTPArray is an object.
In your lists object, initialize an empty array called timeAndOTPArray
var index = lists.findIndex(function(item){ return item.ID == req.params.ID});
lists[index].timeAndOTPArray.push(timeAndOTPArray);

Getting the latest documents from a Cloudant/CouchDB database from NodeJS

I would like to take the last n documents from my Cloudant database using a Node query. So far I have narrowed it down to the find() function, but the documentation only really explains how to retrieve all documents containing an absolute value, for example:
db.find({selector:{name:'Alice'}}, function(er, result) {
...
});
(taken from https://www.npmjs.com/package/cloudant#cloudant-query)
What I'm looking for is the equivalent of this SQL:
SELECT * FROM db WHERE name = "Alice" LIMIT 10
The code I have so far is this:
var cloudant = require('cloudant');
cloudant({account: username, password: password}, function (err, conn) {
if (err) {
callback("Could not initialize connection to Cloudant: " + err);
} else {
var db = conn.db.use('mydb');
db.find(???, function(err, data) {
if (err) {
callback("No data found: " + err);
} else {
...
}
});
}
});
If I need to make design documents, I'd do so in the Cloudant online interface, so don't worry too much about making an executable answer for that if it's necessary.
It's important to note that Cloudant Query requires you to define your index before performing the query e.g. to index the 'name' field from your documents:
db.index( {name:'nameindex', type:'json', index:{fields:['name']}}
We can now query the data using the find function as you indicated:
var query = { selector: { name: 'Alice' }};
db.find(query, function(err, data) {
});
The interesting thing about your question is the phrase 'the last n documents'. We can retrieve 'n' documents by adding a 'limit' to our query.
var query = { selector: { name: 'Alice' }, limit: 10};
db.find(query, function(err, data) {
});
but this doesn't necessarily indicate the last ten documents; it just limits the result set to ten.
If you want your query results to appear in time order, then you'll need something in your documents that indicates the time e.g.
a time string : { "name": "Alice", "datetime": "2015-11-26 10:22:24 Z" }
a timestamp : { "name": "Alice", "ts": "123456678" }
When your document contains a field which represents time, then your index can be created incorporate this into the index e.g.
db.index( {name:'nameindex', type:'json', index:{fields:['name','time']}}
and documents can be queried to appear in *reverse order * (to get the latest first):
var query = { selector: { name: 'Alice' }, sort: [ { name: "desc"}, { ts: "desc"]};
db.find(query, function(err, data) {
});
You may also want to look at type:"text" indexes too. See https://docs.cloudant.com/cloudant_query.html
var query = { selector: { name: 'Alice' }, sort: [ { name: "desc"}, { ts: "desc"]};
should be
var query = { selector: { name: 'Alice' }, sort: [ { name: "desc"}, { ts: "desc"}];

Exclude fields from result in MongoDB monk

I want to exclude some fields from result.
I have code:
users = db.select('users');
users.find( {}, { sort: { points:1 }, privateKey:0, publicKey:0}, function(err,data){
res.send(data);
});
I want to exclude private and public key from results.
Can I do that using monk?
You can also do it like this:
users.find( {}, { sort: { points:1 }, fields : { privateKey:0, publicKey:0} },
function(err,data){
res.send(data);
}
);
According to documentation first argument in find is filter and second is projection .But you have used sort . It will not able to interpret . You are trying to confuse projection with sort .Sorting should be after find and projection.
You can write projection like { field1: <boolean>, field2: <boolean> ... }
Note :
The find() method always includes the _id field even if the field is not explicitly stated to return in the projection parameter.
users.find({}, { privateKey: 0, publicKey: 0 }).sort({points: 1}).toArray(
function (err, data) {
res.send(data);
});
For me, I need to use the .project() method:
const someFunction = async () => {
const result = await users
.find({}, { sort: { points: 1 })
.project({ privateKey: 0, publicKey: 0});
};
This is what worked for me for excluding the _id field.
const courseChapters = await db
.collection("users")
.find({}, { projection: { _id: 0 } })
.toArray();
So the example in the question would look something like this.
users.find(
{},
{ projection: { points: 1, privateKey: 0, publicKey: 0 } },
function (err, data) {
res.send(data);
}
);
Check out this other answer that says you may need the fields field instead of projection depending upon your driver

Order and limit results in a query with a callback

Using Mongoose, I'd like to make a query with MongoDB and order and limit the results I get. I am doing this with Node.js so I am using callbacks.
So far, I have managed to order my results like this:
myModel.find({ $query: {}, $orderby: { created_at : -1 }}, function (err, items) {
callback( null, items )
});
How can I limit the results I get selecting and index and the number of items I want to get?
Using mongodb native:
http://mongodb.github.io/node-mongodb-native/api-generated/collection.html#find
myModel.find(filter)
.limit(pageSize)
.skip(skip)
.sort(sort)
.toArray(callback);
You can also specify the items in your query:
myModel.find(filter, {sort: {created_at: -1}, limit: 10}, function(err, items){
});
There is no $orderby in node mongodb native, so I'm not sure what library or other tool you're using.
...
Now that you've clarified Mongoose (which in general I recommend against):
myModel.find(filter).limit(10).exec(function(err, items){
//process
});
To sort documents, we can apply sort on a cursor object. To enforce order of sort, instead of passing an object, we need to pass an array to the sort method.
var MongoClient = require('mongodb').MongoClient,
commandLineArgs = require('command-line-args'),
assert = require('assert');
var options = commandLineOptions();
MongoClient.connect('mongodb://localhost:27017/crunchbase', function(err, db) {
assert.equal(err, null);
console.log("Successfully connected to MongoDB.");
var query = queryDocument(options);
var projection = {
"_id": 0,
"name": 1,
"founded_year": 1,
"number_of_employees": 1
};
var cursor = db.collection('companies').find(query);
cursor.project(projection);
cursor.limit(options.limit);
cursor.skip(options.skip);
cursor.sort([
["founded_year", 1],
["number_of_employees", -1]
]);
var numMatches = 0;
cursor.forEach(
function(doc) {
numMatches = numMatches + 1;
console.log(doc.name + "\n\tfounded " + doc.founded_year +
"\n\t" + doc.number_of_employees + " employees");
},
function(err) {
assert.equal(err, null);
console.log("Our query was:" + JSON.stringify(query));
console.log("Documents displayed: " + numMatches);
return db.close();
}
);
});
function queryDocument(options) {
console.log(options);
var query = {
"founded_year": {
"$gte": options.firstYear,
"$lte": options.lastYear
}
};
if ("employees" in options) {
query.number_of_employees = {
"$gte": options.employees
};
}
return query;
}
function commandLineOptions() {
var cli = commandLineArgs([{
name: "firstYear",
alias: "f",
type: Number
}, {
name: "lastYear",
alias: "l",
type: Number
}, {
name: "employees",
alias: "e",
type: Number
}, {
name: "skip",
type: Number,
defaultValue: 0
}, {
name: "limit",
type: Number,
defaultValue: 20000
}]);
var options = cli.parse()
if (!(("firstYear" in options) && ("lastYear" in options))) {
console.log(cli.getUsage({
title: "Usage",
description: "The first two options below are required. The rest are optional."
}));
process.exit();
}
return options;
}
One thing to notice is the order in which MongoDB applies skip, limit and sort
sort
skip
limit
There's also a possibility that we can sort data on the MongoDB side as well, provided that we've setup the indexing.
Notice that MongoDB driver will send a query when we call a cursor method passing a callback function to process query results.

Resources