MongoDB average aggregation using NodeJS - node.js

Good afternoon everyone.
I have an Array inside a MongoDB Document. I wan't to find a Volume inside it and make an average for whole collection on Volume parameter.
Document inside a MongoDB:
As you can see I have array inside array. I will have a lot of the same type documents and I need to make an average calculation between every document on Volumeparameter.
Problematic area of code(This is not working just showcasing my try.
function simplePipeline(db, callback) {
const collection = db.collection('ADABTC');
collection.aggregate(
[
{ '$group': { 'Volume': { '$avg': 'Array.Volume' } } }
],
function(err, cursor) {
assert.equal(err, null);
cursor.toArray(function(err, documents) {
console.log(documents)
callback(documents);
});
}
);
}
Just in case I can connect to DB username:password just for example.
How I should specify it NodeJS?
NodeJS Full Code
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://username:password#ip.adress.port/<dbname>?retryWrites=true&w=majority';
// Database Name
const dbName = 'Crypto';
// Create a new MongoClient
const client = new MongoClient(url, { useUnifiedTopology: true });
// Use connect method to connect to the Server
client.connect(function(err, client) {
assert.equal(null, err);
console.log("Connected correctly to server");
const db = client.db(dbName);
simplePipeline(db, function() {
client.close();
});
});
function simplePipeline(db, callback) {
const collection = db.collection('ADABTC');
collection.aggregate(
[
{ '$group': { 'Volume': { '$avg': 'Array.Volume' } } }
],
function(err, cursor) {
assert.equal(err, null);
cursor.toArray(function(err, documents) {
console.log(documents)
callback(documents);
});
}
);
}

Your $group syntax is just wrong:
Groups input documents by the specified _id expression and for each distinct grouping, outputs a documen
A $group stage must have a _id field specified. to group the entire collection just put any constant there.
{
'$group': {
_id: null,
'Volume': {
'$avg': '$Array.Volume'
}
}
}

Related

I want to apply my MongoDB query to Javascript(select specific column)

Hi I'm working with my MongoDB and NestJS.
I was testing by query below. And it was what I expected
I only want to get '_id'. So I tested my code too.
// // This is what I use(including comments)
// const { MongoClient, ObjectID } = require('mongodb');
// const url = 'mongodb+srv://alex:~ something';
// console.log(url);
// const client = new MongoClient(url);
// // Database Name
// const dbName = 'testDB';
export async function getCreaterPubGameId(authorID: string) {
await client.connect();
console.log('Connected successfully to server : update, find or insertData');
const db = client.db(dbName);
const collection = db.collection('games');
return new Promise(function (resolve, reject) {
collection.find({ authorID }, { type: '_id' }).toArray((err, doc) => {
if (err) {
reject(err);
} else {
console.log('getAlldata : ', doc);
resolve(doc);
}
});
});
}
After I use this function, I got all the data from MongoDB.
As you see, I used the same syntax. But I got all the data.
Is there anybody who has a good idea??
You need to use projection when using MongoDb Node.js client.
export async function getCreaterPubGameId(authorID: string) {
await client.connect();
console.log('Connected successfully to server : update, find or insertData');
const db = client.db(dbName);
const collection = db.collection('games');
return new Promise(function (resolve, reject) {
collection.find({ authorID }, { "type": 1}).toArray((err, doc) => {
if (err) {
reject(err);
} else {
console.log('getAlldata : ', doc);
resolve(doc);
}
});
});
}
When you pass 1 to any field, it will be added to the prjection field and will only show those schema field. By default _id will be included if you want to not include it pass _id: 0.
export async function getCreaterPubGameId(authorID: string) {
await client.connect();
console.log('Connected successfully to server : update, find or insertData');
const db = client.db(dbName);
const collection = db.collection('games');
// I have to use 'projection'
return new Promise(function (resolve, reject) {
collection.find({ authorID }, { projection: { _id: true }).toArray((err, doc) => {
if (err) {
reject(err);
} else {
console.log('getAlldata : ', doc);
resolve(doc);
}
});
});
}
Link : https://mongodb.github.io/node-mongodb-native/3.2/api/Collection.html#find

mongodb changestream “pipeline” not working nodejs

I have the following change stream but it does not function changed is not logged once I update using mongo compass.
var pipeline = [
{ $match: { _id: ObjectId(id) } }
];
try {
const collection = client.db("mydb").collection("shop");
const changeStream = collection.watch(pipeline);
changeStream.on('change', (next) => {
//console.log(next);
console.log('changed')
}, err => {
console.log(err);
});
} catch (err) {
console.log(err)
}
Is the problem that you don't normally update the _id of a document in a collection? If, for some reason, you are updating the _id then maybe the problem is in how you're referencing your $match. This works for me:
const pipeline01 = [
{ $match: { 'updateDescription.updatedFields.fieldIamInterestedIn': { $ne: undefined } } },
{ $project: { 'fullDocument._id': 1, 'fullDocument.anotherFieldIamInterestedIn': 1 } },
];
theCollectionIamWatching.watch(pipeline01, { fullDocument: 'updateLookup' }).on('change', async (data) => {
// do the thing I want to do using data.fullDocument
});

How to get all data matched each record from mongodb using mongoose and nodejs

Tried to get value of product_name from my mongodb using mongoose but i do not know how to do it.
My DB Data collection:
{
_id:ObjectId("5ecea02ebb6f3c19e86fe805"),
product_name:"Test1"
},
{
_id:ObjectId("5ecea02ebb6f3c19e86fe806"),
product_name:"Test2"
},
{
_id:ObjectId("5ecea02ebb6f3c19e86fe807"),
product_name:"Test3"
},
{
_id:ObjectId("5ecea02ebb6f3c19e86fe808"),
product_name:"Test4"
},
{
_id:ObjectId("5ecea02ebb6f3c19e86fe809"),
product_name:"Test5"
}
data.controller.js:
module.exports.getData = (req, res, next) => {
var tableCate = mongoose.model("Product");
tableCate.find({ product_name }, function(err, docs) {
if (err) {
console.log( err);
return
} else {
console.log(docs)// output should be Test1,Test2,Test3,Test4,Test5
}
});
db.collection.find returns a Cursor which is A pointer to the result set of a query, to access the result you can use db.collection.find({}).toArray() to return an array of documents or
.forEach(function(item){
// and you can print or do what you want with each item
})

MongoError unknown group operator

I am using MongoDb Driver for NodeJS.
I am facing issues in using aggregation.
The error is
{"name":"MongoError","message":"unknown group operator
'_id'","ok":0,"errmsg":"unknown group operator '_id'","code":15952}
for the below script :
MongoClient.connect(url, function (err, db) {
if (err)
{
console.log('Unable to connect to the mongoDB server. Error:', err);
return;
}
var collName = "order";
var whereParas = {};
var groupParas = {"_id":null,total:{$sum:"$Value"}};
var havingParas = {};
db.collection(collName).aggregate(
[
{ $match: whereParas },
{
$group: { groupParas}
},
{ $match: havingParas }
]).toArray(function (err,result) {
console.log("err");
console.log(err);
console.log("result");
console.log(result);
});
});
The data used is
Desired Output is Sum of Values.
In sql, I would have written :
Select Sum(Value) From order
The group pipeline should be { $group: groupParas } instead of { $group: { groupParas } } hence the error you are getting as Mongo is trying to interpret the nested document win the object as the _id group operator.

nodejs mongoose bulk update

I have a collection of documents and I need to add a new field for ever document. If I run a query to get all documents and then update every single one node.js is stopped, may be for memory leak
This is my code
var express = require('express');
var geocoderProvider = 'google';
var httpAdapter = 'http';
var People = require("./models/people").collection.initializeOrderedBulkOp();
var app = express();
var geocoder = require('node-geocoder').getGeocoder(geocoderProvider, httpAdapter, {});
app.get('/', function (req, res) {
People.find({}, function (err, docs) {
if (err) {
res.send(err);
}else{
docs.forEach( function (doc){
geocoder.geocode({address: doc.address, country: 'Italy', zipcode: doc.cap}, function(error, value) {
doc.loc.coordinates[0]=value[0].latitude;
doc.loc.coordinates[1]=value[0].longitude;
People.update({ _id: doc._id }, { $set: { loc: doc.loc }}, { multi: true }, function (error){
if(error){
console.error('ERROR!');
}
});
});
});
}
});
});
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('Example app listening at http://%s:%s', host, port)
});
There is any way to bulk update with mongoose?
Thanks in advance
More detailed info about the query and update query.
var bulk = People.collection.initializeOrderedBulkOp();
bulk.find(query).update(update);
bulk.execute(function (error) {
callback();
});
Query is searching with array.
Update needs a $set
var bulk = People.collection.initializeOrderedBulkOp();
bulk.find({'_id': {$in: []}}).update({$set: {status: 'active'}});
bulk.execute(function (error) {
callback();
});
Query is a searching the id
var bulk = People.collection.initializeOrderedBulkOp();
bulk.find({'_id': id}).update({$set: {status: 'inactive'}});
bulk.execute(function (error) {
callback();
});
You can drop down to the collection level and do a bulk update. This action will not be atomic - some of the writes can fail and others might succeed - but it will allow you to make these writes in a single round trip to your database.
It looks like this:
var bulk = People.collection.initializeUnorderedBulkOp();
bulk.find({<query>}).update({<update>});
bulk.find({<query2>}).update({<update2>});
...
bulk.execute(function(err) {
...
});
Check out the docs here: http://docs.mongodb.org/manual/core/bulk-write-operations/
This example should include all the cases that we can mix together using directly with Mongoose bulkWrite() function:
Character.bulkWrite([
{
insertOne: {
document: {
name: 'Eddard Stark',
title: 'Warden of the North'
}
}
},
{
updateOne: {
filter: { name: 'Eddard Stark' },
// If you were using the MongoDB driver directly, you'd need to do
// `update: { $set: { title: ... } }` but mongoose adds $set for
// you.
update: { title: 'Hand of the King' }
}
},
{
deleteOne: {
{
filter: { name: 'Eddard Stark' }
}
}
}
]).then(res => {
// Prints "1 1 1"
console.log(res.insertedCount, res.modifiedCount, res.deletedCount);
});
Official Documentation: https://mongoosejs.com/docs/api.html#model_Model.bulkWrite

Resources