Unable to increment field in mongodb using mongoose - node.js

I have a document in mongodb. The document in This function is able to find the document and it returns it but I can't for the life of me get this function to update the count field by 1. The current document in mongodb if it helps is:
{
_id: 60c5e4c3fba7edd232cf57e7,
counterName: 'give_me_the_count',
count: 1,
updatedAt: 2021-06-13T11:47:02.575Z
}
The code is returning the original document to updatedCounter. But updatedCounter.count is undefined.
async function updateAndReturnNewCount() {
let doc = await Counter.findOne({ counterName : "give_me_the_count" })
var count = doc.count
let updatedCounter = await Counter.findOneAndUpdate({ counterName : "give_me_the_count" },
{ $inc: {"count" : 1 }},
{ new: true,
useFindAndModify: false },
function(err, doc) {
if (err) { console.log(err)}
else {console.log("success")}
}
);
console.log("updateAndReturnNewCount fired")
return updatedCounter.count
}

Your query is incorrect for the operation you wanted to do.
Try this one:
await Counter.aggregate([
{
$match: {
counterName : "give_me_the_count"
}
},
{
$set: {
"count": {
$add: [ "$count", 1 ] // Increment $count by one
}
}
}
])
Playground
Edit:
Usage:
async function updateAndReturnNewCount() {
let doc = await Counter.findOne({ counterName : "give_me_the_count" })
var count = doc.count
let updatedCounter = await Counter.aggregate([
{
$match: {
counterName : "give_me_the_count"
}
},
{
$set: {
"count": {
$add: [ "$count", 1 ] // Increment $count by one
}
}
}
])
console.log("updateAndReturnNewCount fired");
console.log(updatedCounter);
return count++;
}

Related

Mongo occurance count by column

I have a usecase to find the count of different statues like active, in-active, in-progress, etc,
the documents look like this -
{
"id": "1"
"status": "active"
},
{
"id": "2"
"status": "active"
},
{
"id": "3"
"status": "in-active"
},
{
"id": "4"
"status": "in-progress"
}
I needed output like -
{
"active": 2,
"in-active": 1,
"in-progress": 1
}
I am referring this answer but, not able to get the expected output -
Mongo count occurrences of each value for a set of documents
My code is as follows -
const mongoClient = require('mongodb').MongoClient;
const test = async () => {
const mongoUri = "mongodb://localhost:27017/";
const dbClientConnection = await mongoClient.connect(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const db = await dbClientConnection.db("database name here");
const collection = await db.collection("collection name here");
let result = await collection.aggregate([
{
$group: {
_id: "$status",
sum: { $sum: 1 }
}
},
{
$group: {
_id: null,
status: {
$push: { k: "$_id", v: "$sum" }
}
}
},
{
$replaceRoot: {
newRoot: { $arrayToObject: "$status" }
}
}
])
console.log("result => ", result);
return result;
}
test();
The first stage is correct
$group by null and construct the array of key and value format
$arrayToObject convert above converted key-value pair array to an object
$replaceRoot to replace above object to root
let result = await collection.aggregate([
{
$group: {
_id: "$status",
sum: { $sum: 1 }
}
},
{
$group: {
_id: null,
status: {
$push: { k: "$_id", v: "$sum" }
}
}
},
{
$replaceRoot: {
newRoot: { $arrayToObject: "$status" }
}
}
])
Playground

what will be mangoose equivalent of this oracle query

I am trying to convert this oracle query to Mongoose equivalent. I am trying to do it using findOneAndUpdate, but don`t know how to convert this NVL thing.
here is my query
Update Authentication
Set Datetime = Sysdate,
Isactive = 'Y',
Version = '1.0.0',
Firstlogin = Nvl(Firstlogin, Sysdate),
Lastlogin = Sysdate
This is what i have tried. I have used $cond and inside it ifNull, but its not working, Also used $cond and then and if condition to check for null, bot no luck at all.
function createOrUpdate() {
let filter = { count: { $lt: 4 } };
let options = { upsert: true, returnOriginal: false, multi: true };
let userID = "asdfasdf"
let testUser = {
userId: userID,
userNick: "user.nickName",
reqTime: 1,
}
let update = {
$inc: { count: 1 }, $addToSet: {
"users": {
$each: [testUser],
}
},
$cond: [
{
$ifNull: ['$roomName', true], $set: {
roomName: "1112"
},
$set: {
roomName: "1112"
}
},
]
};
// { },
// let update = {
// $cond: {
// if: {
// $or:[{$eq: ["roomName",null]},{$eq: ["roomName",""]}]
// },
// then: {
// $set: {
// roomName: "varxy"
// }
// },
// else: {
// $set: {
// roomName: "roomName"
// }
// }
// },
// $inc: { count: 1 },
// "$set": { "users":{ "userId": userID, "user": testUser } }
// }
ModelRooms.findOneAndUpdate(
filter,
update,
options, function (err, doc) {
if (err) {
logger.error(`Error:: ${err}`);
}
else {
logger.info(`User added to room`);
}
});
}

How to update the increment counter of nested array of objects under array of objects

I have an nested data structure like this:
{
"_id" : ObjectId("5f51362883fc9424bcc3ed76"),
"count" : [
{
"page" : "SHOE",
"visit_count" : 2,
"guestip" : [
{
"ip" : "192.168.1.4",
"visit" : 1
},
{
"ip" : "192.168.1.5",
"visit" : 1
}
]
},
{
"page" : "TSHIRTS",
"visit_count" : 2,
"guestip" : [
{
"ip" : "192.168.1.1",
"visit" : 1
},
{
"ip" : "192.168.1.2",
"visit" : 1
}
]
}
],
"createdate" : ISODate("2020-09-03T18:30:00.056Z"),
"__v" : 0
}
How I can increment the visit counter for 192.168.1.2 ip ib TSHIRTS section.
What I tried:
I am using node.js and mongoose;
const isIPExists = (ip, arr) => arr.some(el => String(el.ip) === ip);
//NOTE: Below code is under async function that is why used the await.
const data = await CollectionName.findOne(
{ createdate: { $gte: finaldate } },
{ assetpage_visit_count: { $elemMatch: { page: req.body.page } } },
).exec();
if (data.count.length === 0) {
//This part works fine
await CollectionName.updateOne(
{ createdate: { $gte: finaldate } },
{
$push: {
count: {
page: req.body.page, //Here let's say TSHIRTS is sending
visit_count: 1,
guestip: [
{
ip: req.body.ip,
visit: 1
}
]
},
},
).exec();
} else {
const storeIpArray = data.count[0].guestip;
let xfilter = {
$inc: {
'count.$.visit_count': 1,
},
$push: {
'count.$.guestip': {
ip: req.body.ip,
visit: 1
}
}
}
if (isIPExists(req.body.ip, storeIpArray) === true) {
xfilter = {
$inc: {
'count.$.visit_count': 1,
'count.$.visit_count.$.visit': 1
},
}
}
await CollectionName.updateOne(
{
createdate: { $gte: finaldate },
'count.page': req.body.page,
},
xfilter,
).exec();
}
return res.send("Done")
}
Any help or suggestion is really appreciated for the increment count under nested structure. Pardon for the indenting as code was very long so just split the issue part here and mentioned the code manually.
Use arrayFilters.
This exactly query is very well explain in the documentation Update Nested Arrays in Conjunction with $[] with copy-pasteable examples.
You just had to update field names to match your documents:
db.CollectionName.update(
{},
{ $inc: { "count.$[p].guestip.$[ip].visit": 1 } },
{ arrayFilters: [
{ "p.page": "TSHIRTS" } ,
{ "ip.ip": "192.168.1.2" }
] })
Please note, the subdocument with source ip "192.168.1.2" must be in the array for $inc to increment it, so you may need to push it with visit:0 before running the update query.

Why am I getting a AggregationCursor as a result and not an average?

I'm querying my MongoDB database and don't understand why I am getting an aggregator cursor as a result when I expect to be returned a single number. Maybe I need to get something from the cursor object? Just can't figure out what.
module.exports = CalculateAvg = async collection => {
try {
// const count = await collection.countDocuments({ word: "Hello" });
// console.log(count) // logs 140, which shows that it is accessing the db correctly
const cursor = await collection.aggregate([
{ $match: { word: "Hello" } },
{
$group: {
_id: null,
mean: {
$avg: "$value" // in the dataset, each doc has a value field which equals a number
}
}
}
]);
console.log(cursor) // logs a large AggregationCursor object, rather than a number
} catch (err) {
console.log(err);
}
};
It's because aggregate return value is aggregateCursor, I recommend checking the Mongo's Nodejs driver types file whenever you're not sure whats the return value or the parameter value for any of these functions is.
You want to use cursor toArray like so:
const cursor = await collection.aggregate([
{ $match: { word: "Hello" } },
{
$group: {
_id: null,
mean: {
$avg: "$value" // in the dataset, each doc has a value field which equals a number
}
}
}
]).toArray();
You should use next() method... For Example
const pipeline = [{
$facet: {
total: [{
$count: 'createdAt'
}],
data: [{
$addFields: {
_id: '$_id'
}
}],
},
},
{
$unwind: '$total'
},
{
$project: {
data: {
$slice: ['$data', skip, {$ifNull: [limit,'$total.createdAt']} ]
},
meta: {
total: '$total.createdAt',
limit: {
$literal: limit
},
page: {
$literal: ((skip/limit) + 1)
},
pages: {
$ceil: {
$divide: ['$total.createdAt', limit]
}
}
}
}
}];
const document = await collection.aggregate(pipeline);
const yourData = await document.next();

Remove _Id from mongoose Aggregate response

I'm trying to remove the _Id from the returned documents, this is my code:
module.exports = function(app) {
// Module dependencies.
var mongoose = require('mongoose'),
Contacts = mongoose.models.Contacts,
api = {},
limit = 10;
api.contacts = function(req, res) {
Contacts.aggregate([{
$group: {
"_id": {
name: "$name",
city: "$city",
state: "$state"
}
}
}, {
$sort: {
AgencyTranslation: 1
}
}, {
$limit: req.query.limit | limit
}],
function(err, contacts) {
if (err) {
res.json(500, err);
} else {
res.json({
contacts: contacts
})
}
})
};
app.get('/api/contacts', api.contacts);
};
the current result-set looks like this:
{
"contacts":[
{"_id":{"name":"Joe","city":"ankorage","state":"AL"}},
{"_id":{"name":"Mark","city":"washington","state":"DC"}}
...
]
}
I tried to replace "_Id" with "$project", or $project, and adding "_Id": 0 to the object, as some have suggested elsewhere, but was not successful.
I also tried res.send(contacts), but that only stripped the super-object ('contacts').
Any suggestions are appreciated.
Like this
Contacts.aggregate( [
{ $group: { "_id": { name: "$name", city: "$city", state: "$state" } } },
{ $project: {_id: 0, name: '$_id.name', city: '$_id.city', state: '$_id.state'} },
{ $sort: { AgencyTranslation: 1 } },
{ $limit: req.query.limit | limit }
], function () {
});
Bunch of time but, here is the answer:
After making $group or $project, do this:
{ $unset: ["_id"] }

Resources