Distinct count with sequelize - node.js

I'm trying to get a distinct count with sequelize such as
'SELECT COUNT(DISTINCT(age)) AS `count` FROM `Persons` AS `Person`'
As long as I use a raw query, I get the desired result. However, as soon as I change to the sequelize count function, the query is broke in Postgres:
Person.count({distinct:'age'}).then(...);
results to
'SELECT COUNT(DISTINCT(*)) AS `count` FROM `Persons` AS `Person`'
which leads to a syntax error. Solutions described in different posts such as How to get a distinct count with sequelize? do not work, unless you add an include statement or a where clause which I do not have in this special case.
Does anybody know a proper solution for this?

You have to use Sequelize aggregation to make it worked correctly.
Model.aggregate(field, aggregateFunction, [options])
Returns: Returns the aggregate result cast to options.dataType, unless
options.plain is false, in which case the complete data result is
returned.
Example:
Person.aggregate('age', 'count', { distinct: true })
.then(function(count) {
//.. distinct count is here
});
Executing (default):
SELECT count(DISTINCT("age")) AS "count" FROM "persons" AS "person";

You can do it something like this :
models.User.findAll({
attributes: ['user_status',[sequelize.fn('COUNT', sequelize.col('user_status')), 'total']] ,
group : ['user_status']
});
That will return something like :
[
{ user_status : 1 , total : 2 },
{ user_status : 2 , total : 6 },
{ user_status : 3 , total : 9 },
...
]
Then you can loop through returned data and check of status

In latest version, you should be doing
Person.count({distinct:true, col: 'age'}).then(...);
See: http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-count

Related

Sequelize raw query not properly printed

I am trying to write query in sequelize but query is not working below is my query that I write in sequelize
var homePosts = db.postbox.findAll({
where: {
user_id: {
$or: {
$eq: id,
$in: [id]
}
}
},
attributes: ["user_posts_id"],
limit: 5
});
return homePosts;
Node js print result query
Executing (default): SELECT `user_posts_id` FROM `user_posts_boxes` AS `user_posts_boxes` WHERE `user_posts_boxes`.`user_id` = '[object Object]' LIMIT 5;
[]
It prints object instead of variable value and print the actual query that sequelize prepare.
My actual raw query is following which I actually want to convert into sequelize
SELECT `user_posts_id` FROM `user_posts_boxes` AS `user_posts_boxes` WHERE ( `user_posts_boxes`.`user_id` = '5' OR `user_posts_boxes`.`user_id` IN (select following_id from friend WHERE friend.follower_id = user_posts_boxes.user_id and friend.status='A' and friend.following_id=5)) LIMIT 5
I had the same issue with Sequelize 5. Use Symbol based operator and it should be fine https://github.com/sequelize/sequelize/issues/8417

Passing variables into a query in mongoose in the first argument

I am using MEAN stack, i have an entry like this in my mongodb
{ "_id" : ObjectId("5577467683f4716018db19ed"),
"requestMatrix" : { "1698005072" : { "rideId" : "641719948", "status" :"accepted" },"1698005073" : { "rideId" : "641719545", "status" :"rejected" } },
"partners":[ { "customerNumber" : 1698005072 }, { "customerNumber" : 1698072688 } ]}
I want to query the db to return me this entire document based on whether the status is accepted or rejected.
When I run the below query in a command prompt, i get the expected answer
db.joinedrides.find({'requestMatrix.1698005072.status':"accepted"})
But when i want to do the same from nodeJs, I am stuck as the number 1698005072 in the above query is a variable, i am not able to write a query for that.
tried something like this
var criteria = "'requestMatrix.'"+customerNumber+"'.status'";
JoinedRide.find({criteria:"accepted"},function(err,joinedRides){
})
where customerNumber will vary for different requests, in the above mentioned case its value is 1698005072
Any help is appreciated.
You need to do something like this:
var query = {};
var criteria = "requestMatrix." + customerNumber + ".status";
query[criteria] = "accepted"
JoinedRide.find(query,function(err,joinedRides){
})

Mongoose collection statistics / manipulations queries

first, a comment. The collection described is simplified, for this question. I'm interesting in understanding how to manipulate a mongo db and get statistics of my data.
Let's say I have a collection with test results. The schema is:
Results {
_id: ObjectId
TestNumber: int
result: String // this contains "pass" or "fail"
// additional data
}
For each test can be many reports, so most likely each TestNumber appears in more than one document.
How can I perform a query which returns this info on the entire collection:
TestNumber | count of result == "pass" | count of result == "fail"
You can use the below aggregation operations pipelined together:
Group all the documents based on their testNumber and the type of
result together, so for every testNumber, we would have two
groups each, one for fail and another for pass, with the count of
documents in each group.
Project a variable "pass" for the group containing the result as
pass, and fail for the other group.
Group together the documents again based on the testNumber, and
push the pass and fail documents into an array.
Project the fields as required.
The Code:
Results.aggregate([
{$group:{"_id":{"testNumber":"$testNumber","result":"$result"},
"count":{$sum:1}}},
{$project:{"_id":0,
"testNumber":"$_id.testNumber",
"result":{$cond:[{$eq:["$_id.result","pass"]},
{"pass":"$count"},
{"fail":"$count"}]}}},
{$group:{"_id":"$testNumber",
"result":{$push:"$result"}}},
{$project:{"testNumber":"$_id","result":1,"_id":0}}
],function(a,b){
// post process
})
Sample Data:
db.collection.insert([
{
"_id":1,
"testNumber":1,
"result":"pass"
},
{
"_id":2,
"testNumber":1,
"result":"pass"
},
{
"_id":3,
"testNumber":1,
"result":"fail"
},
{
"_id":4,
"testNumber":2,
"result":"pass"
}])
Sample o/p:
{ "result" : [ { "pass" : 1 } ], "testNumber" : 2 }
{ "result" : [ { "fail" : 1 }, { "pass" : 2 } ], "testNumber" : 1 }
iterating doc.result will give you the pass count and the number of failed tests for the testNumber.

Nodejs mongo return data with pagination information

I am using node and mongo with the native client.
I would like to add pagination to my application.
To get pagination, I need my responses to always return count alongside data
I would like to get something like:
{
count : 111,
data : [ { 'a' : 'only first item was requested' } ]
}
I can do this in mongo
> var guy = db.users.find({}).limit(1)
> guy.count()
11
> guy.toArray()
[
{
"_id" : ObjectId("5381a7c004fb02b10b557ee3"),
"email" : "myEmail#guy.com",
"fullName" : "guy mograbi",
"isAdmin" : true,
"password" : "fe20a1f102f49ce45d1170503b4761ef277bb6f",
"username" : "guy",
"validated" : true
}
]
but when I do the same with nodejs mongo client I get errors.
var cursor = collection.find().limit(1);
cursor.toArray( function(){ .. my callback .. });
cursor.count();
It seems that
count is not defined on cursor
that once I applied toArray on cursor, I cannot use the cursor again
How, using nodejs, can I accomplish the same thing I can with mongo directly?
As others have said, if you want to have a total count of the items and then the data you will need to have two queries, there is no other way. Why are you concerned with creating two queries?

MongoDB Location NearBy unique

I have created a collection in DB and updated with proper indexing to retrieve it back. Im getting with the folloging
Example:
db.car.save({ "name":"Toyota car", "affiliation":"Toyota", "loc":{"lon":55.93939251390387,"lat":-113.999}})
db.car.find({"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}})
I have 100K + records in Database when I search the above query returns 20K records.
Actually this has some duplicate values in the "name" column. How can I get the distinct value of "name".
You can't get the results you need using a query in MongoDB 2.0.x, so will need to manipulate the results in your application code.
If you are only after names you can limit the fields in the output:
db.car.find(
{"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}},
{"_id": 0, "name": 1}
)
If you want to find distinct names you could do something like:
// Save cars we've seen
> var cars_seen = {}
// The unique list we actually want
> var cars = []
// Find closest cars to given geo point
> db.car.find(
{"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}},
{"_id": 0, "name": 1}
).forEach(
function(doc) {
// Add names we haven't seen yet
if (!cars_seen[doc.name]) {
cars_seen[doc.name] = 1;
cars.push(doc.name);
}
}
)
> cars
[ "Skoda", "Benz", "Skoda SUV" ]

Resources