mongodb get collection.aggregate reponse sorted - node.js

i have a nodejs server with mongodb database and a collection with the following structure:
{user_id: int, country: string}
i need to get the country name that have the most users from.
currently what i do is get collection.distinct to get unique countries, and after that i run aggregate query to get the count and finally i sort the response_array manually to get the highest count, my question is what i need to add to the query in order to get the data sorted from the database so i wont need to sort it after the response?
let query = {};
for (let i = 0; i < countries.length; i++)
{
let country = countries[i];
query[country] = [{
$match: { country: country}
}, { $count: "count" }]
}
let response_cursor = await collection.aggregate([{$facet: query}]);
let response_array = await response_cursor.toArray();
//sorting the response_array

Related

Mongoose get nested document using another field

Assume that I have a document inside a collection
{
_id: "3434v4vcvc254t34vtds",
currentItemId: "v281",
items: {
v279: [/*Some Data*/],
v280: [/*Some Data*/],
v281: [/*Some Data*/]
}
}
I need to fetch current item.
However I can do it with using two query
let data= await schema.findById("3434v4vcvc254t34vtds", {currentItemId});
let itemId = `items.${data.currentItemId}`
let item = await schema.findByID("3434v4vcvc254t34vtds", { [itemId] })
I need to fetch current item using one query.
Use populate after findById.
const data = await schema.findById('3434v4vcvc254t34vtds').populate('currentItemId').exec()

How to get lastest inserted record _id in mongoose

I am trying to get recently inserted record _id and p_id but i do not know how to get the value.Below given my code.This is not working.How to do it?
DB records:
{
_id:5eba58f0e5def333ad4d8c8d,
p_id:"C1",
product_name:"Name",
product_weight:123
},
{
_id:5eba58f0e5def333ad4d8c8e,
p_id:"C2",
product_name:"Name",
product_weight:123
},
{
_id:5eba58f0e5def333ad4d8c8f,
p_id:"C3",
product_name:"Name",
product_weight:123
}
data.controller.js:
var Product = mongoose.model(collectionName);
let latest_id = Product.findOne().sort({ field: 'asc', _id: -1 }).limit(1);
console.log("_id" + val); //output should be 3
let latest_p_id = Product.findOne().sort({ field: 'asc', p_id: -1 }).limit(1);
console.log("p_id" + val); //output should be C3
MongoDB does not natively support incremental auto generated numbers, so your first case, it's not possible if you don't manage your counter separately. You can count the number of documents, but it won't account for deleted documents.
For the second case, you almost got it:
with async/await
const product = await Product.findOne().sort({ p_id: -1 }).limit(1)
console.log(product.p_id) // this will be your desired output
without async/await
Product.findOne().sort({ p_id: -1 }).limit(1).then((product) => {
console.log(product.p_id) // this will be your desired output
})

Mongo Query, Find whether a string is present in an array

Person = { name: string}
const names = {John, Mark, Fady}
how to make a find query to get all the persons that their names are in the array?
i could make a loop over the array and make a find query for every element but this will not be efficient since it will make N find queries.
db.collection.find( { name: { $in: ['John', 'Mark', 'Fady' ] } } )

how to get one page data list and total count from database with knex.js?

I have a user table with some records(such as 100), how can I get one page data and total count from it when there are some where conditions?
I tried the following:
var model = knex.table('users').where('status',1).where('online', 1)
var totalCount = await model.count();
var data = model.offset(0).limit(10).select()
return {
totalCount: totalCount[0]['count']
data: data
}
but I get
{
"totalCount": "11",
"data": [
{
"count": "11"
}
]
}
, how can I get dataList without write where twice? I don't want to do like this:
var totalCount = await knex.table('users').where('status',1).where('online', 1).count();
var data = await knex.table('users').where('status',1).where('online', 1).offset(0).limit(10).select()
return {
totalCount: totalCount[0]['count']
data: data
}
Thank you :)
You probably should use higher level library like Objection.js which has already convenience method for getting pages and total count.
You can do it like this with knex:
// query builder is mutable so when you call method it will change builders internal state
const query = knex('users').where('status',1).where('online', 1);
// by cloning original query you can reuse common parts of the query
const total = await query.clone().count();
const data = await query.clone().offset(0).limit(10);

Mongo Groupby Aggregate Based on "Key" Not Value

I am stuck with mongo query. I have a mongo collection structure which i can not modify at this time as it is very large data.
I need to carry out some results from the collection , so tried all ways round to get it.
Here is my collection json schema:-
{
"date": "2017-01-01T00:00:00.000Z",
"bob":"P",
"jacob":"P",
"wilson":"A",
"dev":"SL"
},
{
"date": "2017-01-02T00:00:00.000Z",
"bob":"P",
"jacob":"A",
"wilson":"A",
"dev":"SL"
},
{
"date": "2017-01-03T00:00:00.000Z",
"bob":"P",
"jacob":"P",
"wilson":"A",
"dev":"SL"
},
{
"date": "2017-01-04T00:00:00.000Z",
"shashikant":"P",
"jacob":"P",
"wilson":"SL",
"dev":"SL"
}
....
As output I am looking for below kind of structure:-
from 1st jan 2017 to 30th jan 2017
bob P 17
bob A 2
wilson P 10
dev SL. 1
.....
I am using loopback for my backend but still i can use normal mongodb query to get the output.
Please help
MongoDB allows $unwind only for the arrays. But you could use a simple mapReduce to achieve what you want:
//Define the time frame here
var from = new Date('2015-01-01T00:00:00.000Z');
var to = new Date('2025-01-01T00:00:00.000Z');
db.getCollection('test').mapReduce(function () {
var keys = Object.keys(this);
//If there is no date found on a record, simply skip
if (!this.date) {
return;
}
var date = new Date(this.date);
//Skip the records that do not fit into [form; to] interval
if (!(date >= from && date <= to)) {
return;
}
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
//Emit each combination of key and value
if (key !== 'date' && key !== '_id') {
emit({key: key, value: this[key]}, {count: 1});
}
}
},
function (key, values) {
var reduced = {count: 0};
for (var i = 0; i < values.length; i++) {
var value = values[i];
//Simply counting the combinations here
reduced.count += value.count;
}
return reduced;
},
{
//Passing the dates to mongo
//so 'from' and 'to' will be avail in map, reduce and finalize
scope: {from: from, to: to},
finalize: function (key, reducedValue) {
//Changing the data structure just for a convenience
return {
propertyName: key.key,
propertyValue: key.value,
from: from,
to: to,
count: reducedValue.count
};
},
out: {inline: 1}
}
);
I tested this in Mongo console, but map-reduces are also supported by mongo native Node.js and for mongoose as well.

Resources