mongoDB query to pass from string to integer and then sum - node.js

I have these fields:
_id: {
contents: [{
duration: "4",
startDate : "2020-10-14",
}, {
duration: "15",
startDate : "2020-11-17",
}],
}
And I need to find the contents that will expire in the next 10 days.
This is the logic I have to follow:
db.collection.find()
If duration > 10 =>
If ((duration - 10) + startDate) ==== today
But I can't transform the duration or startDate into number, or even how to do the conditional properly

So for this ive made a collection in my mongo local that has a field that has numbers in it like the below image
Now to find sum of durations that are greater that 2....
Now as u see above the trick is to treat the comparator as a string as well.
Lemme attach a node snippet with mongoose as well
var mongoose = require('mongoose');
var mongoDB = 'mongodb://127.0.0.1/my_database';
mongoose.connect(mongoDB, {useNewUrlParser: true, useUnifiedTopology: true});
var db = mongoose.connection;
var Schema = mongoose.Schema;
var SomeModelSchema = new Schema({
duration: String
});
var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
SomeModel.aggregate([{ $match: {duration: { $gt : "2" }}},{ $group: { _id : null, sum: { $sum: {$toDouble: "$duration" }} } }], function(err, data){
console.log(data)
});
db.on('error', console.error.bind(console, 'MongoDB connection error:'));

Strings can not take advantages of numbers operations with indexes. If the table is too big that could end up with a very slow query.
Question 1: why are that fields inserted as string (just curious)
Question 2: why not update all to add a new field 'expiration' with exactly the moment (date or Unix time). That way is easy for the database find those records.

Related

How to save date type dd/mm/yyyy format in mongodb

Tried to save date format like dd/mm/yyyy in mongodb but this is saved like 2020-06-01T18:30:00.000Z.I want to save like 2020-06-01 in mongodb.How to do it?
Here my code:
data.model.js:
const mongoose = require('mongoose');
var userSchemaData = new mongoose.Schema({
p_id: {
type: String
},
product_today: {
type: Date
},
product_afterfive: {
type: Date
}
}, {
versionKey: false,
collection: 'data'
});
module.exports = mongoose.model('Data', userSchemaData);
data.controller.js:
var moment = require('moment');
var todayDate = new Date();
var afterfiveDays = new Date(new Date().getTime() + (5 * 24 * 60 * 60 * 1000));
module.exports.insertData = (req, res, next) => {
let collectionName = req.query.collection;
var Product= mongoose.model(collectionName);
var todayDateFormat = moment(todayDate, 'DD-MM-YYYY').format('MM-DD-YYYY');
var afterfiveDaysFormat = moment(afterfiveDays, 'DD-MM-YYYY').format('MM-DD-YYYY');
var product = new Product({
p_id: "CS1",
product_today:todayDateFormat,
product_afterfive: afterfiveDaysFormat
});
product.save(function(error, document) {
if (error) { console.log(error); } else {
console.log("Successful inserted");
res.json({ success: true, msg: 'User inserted.', cname: collectionName });
}
});
As stated in the documentation, mongoose will create a native Date object from the provided date value (see https://mongoosejs.com/docs/tutorials/dates.html)
The reason for this is probably that MongoDB's underlying type for "date" is
BSON Date is a 64-bit integer that represents the number of
milliseconds since the Unix epoch (Jan 1, 1970). This results in a
representable date range of about 290 million years into the past and
future.
so there's no date-type without the time. You can make sure in your application-code to insert dates with the time set to 00:00:00 or store the the "YYYY-MM-DD"-value as a String instead of a Date.

Mongoose can't query only a database

I'm facing a Mongoose's strange behaviour.
Let's analyse this simple stupid code.
var mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/sodatest', {
useMongoClient: true
});
var db = mongoose.connection;
var OriginalSchema = mongoose.Schema({
addedd: Date,
endPoint: Object,
inserted: Number,
total: Number
});
var OtherTestSchema = mongoose.Schema({
what: String,
modified_at: Date
});
var EndPointInTheDb = mongoose.model('aaa', OriginalSchema);
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("we are connected!");
});
EndPointInTheDb.find({}, (err: String, exit: any) => {
console.log("Errore : " + err)
console.log(exit)
});
It fails and return
we are connected!
*********************
Error : null
[]
*********************
It fails because the collection "aaa" has 15 elements.
If I change the db "sodatest" with any other ( except for another one with a lowercase name ) and 'aaa' with another collection name, it does't care if I use the correct case, it returns a correct result.
we are connected!
*********************
Error : null
[ { _id: 59f76203592b426a16b8b32f,
modified_at: 2017-10-30T17:31:47.622Z,
last_position: 5,
what: 'CONTATOREGEOKEY',
__v: 0 } ]
*********************
(it works also with multiple elements)
I've tried to copy the db in another one,
db.copyDatabase("sodatest","Prova14")
with a name with at least an uppercase char (Prova14), but again no result.
I've checked for hours if I've misspelled a name, but really, I'm sure of it.
I can't understand why it works with any other db ( 14 others with heterogeneous schema) also if I use a schema ("OtherTestSchema" ) that does not match with the collection real schema.... but not with sodatest.
Any Idea ?
Mongoose automatically adds an 's' at the end of the collection name if one is not provided. For Example:
// This will create a collection called 'aaas' since 'aaa' is passed as the
// model name
var EndPointInTheDb = mongoose.model('aaa', OriginalSchema);
// This is how you declare your collection name with a custom collection 'aaa'
var CorrectEndPointInTheDbToCollection = mongoose.model('aaa', OriginalSchema, 'aaa');
CorrectEndPointInTheDbToCollection.find({}, function(err, docs){
console.log(docs)
})
So the initializer for mongoose is mongoose.model('model name', Schema, 'optional collection name'). Highly recommend you pass in the collection name so you know it's pointing to the right collection

Purging Data Logic in MongoDb based on Dates

I am unable to think of logic for the following Issue.
Consider I want to Store Data in mongoose in collection called packet where I can store data of different users. I want to purge the data once a certain threshold has been reached (Say for example 10 days). We know that the Mongoose by default gives us CreatedAt and UpdatedAt fields.
Suppose my data is created at 22nd February 2015 and Current Date is 24th February 2015.I will have a PurgeData number(column used for purging of data) as 2 (difference between the two dates). Every day I want to change the value of the PurgeData number by comparing the difference between the current date and the CreatedAt date. I want to schedule this operation every day and delete the data that has reached the threshold so I save memory space. Can Somebody help me with the logic for it and scheduling of the event?
Thanks in Advance
Haven't actually tried this but I would suggest some logic like schedule a job using the mongo-scheduler package where you first do an update and then remove the documents that breach the PurgeData condition. Something like this (untested):
/*
Scheduler Arguments
connection - mongodb connections string (i.e.: "mongodb://localhost:27017/scheduler-db") or a mongoose connection object
options - Options object
*/
var mongoose = require('mongoose');
var Scheduler = require('mongo-scheduer');
var scheduler = new Scheduler(connection, options);
var packet = new mongoose.Schema({
CreatedAt : {type : Date, default: Date.now},
PurgeData : {type : Number, index : true}
});
var Packet = mongoose.model('Packet', packet);
var moment = require('moment');
//Schedule the event.
var event = {
name: 'purge',
collection: 'packet',
after: new Date(),
cron: "0 15 10 * * ?" //cron string representing a frequency - fire at 10:15am every day
};
scheduler.schedule(event)
scheduler.on('purge', function(packet, event) {
console.log(packet.PurgeData)
Packet.find({"PurgeData": {"$lt": 10} }, function (err, packets) {
packets.forEach(function (p){
var days_diff = moment().diff(moment(p.CreatedAt), 'days') // using momentjs library
Packet.update(
{
"_id": p._id
},
{
"$set": {
PurgeData: days_diff
}
}, function (err, doc){
console.log(doc);
});
});
});
Packet.find({"PurgeData": {"$gte": 10} }, function (err, packets) {
packets.forEach(function (p){
Packet.remove({ "_id": p._id }, function (err){
handleErr(err);
});
});
});
})

Nodejs: Moongoose can't find the object

So I have a mongodb on mongolabs that looks something like this:
under the collection "news"
[{
"_id": {
"$oid": "542aab88e4b0e67da1edd1bd"
},
"year": 2014,
"data": {
"someinfo":"cool info"
}
}]
And on node I have the following:
//dependencies
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
//Setting up the schemas
var newsSchema = new Schema({
year: String,
data: Object
});
mongoose.model('news',newsSchema);
//routes
var mongolabs = express.Router();
mongolabs.route('/List/:type1/:year')
.get(function(req, res){
mongoose.model(req.params.type1).find({year:req.params.year}, function(err,suc) {
res.jsonp(suc);
});
});
app.use('/mongo', mongolabs);
unfortunately when I go http:///mongo/List/news/2014, it returns empty.
I already tried everything I can think of, needless to say I am a newbie to mongoose, node and mongodb.
You're trying to query for a number value with a string value, hence the empty results.
Try casting the req.params.years as a number by adding the unary plus before your param.
{ year: +req.params.year }
You also could use the parseInt() function:
var year = parseInt(req.params.years, 10);
Probably you're passing null to the .find() method.
You're doing this:
{ year: req.params.type1.year }
,when you should be doing:
{ year: req.params.year }

how to get number of documents which is created today with mongoose?

how to get number of documents which is created today with mongoose? I'm using MEAN stack. I read Mongoose Api Docs but doesn't understand anything :/
By default there is no way.
Documents don't have creation date associated with them unless you explicitly store it in MongoDB.
In other words your Mongoose schema should have something like created field:
const blogSchema = new Schema({
created: {type: Date, default: Date.now}
});
Then search for matching docs:
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
doc.find({created: {$gte: today}}).exec(callback);
Supposing you have the date field createdAt in your schema and you would like to get the number of users registered today, you should create a two date object instances to use in your date range query, start and end dates.
Your start date object should hold the current date time hours at 00:00:00.000 (milliseconds precision) and set the hours for today's date to 23:59:59.999 to the end date variable:
var start = new Date();
start.setHours(0,0,0,0);
var end = new Date();
end.setHours(23,59,59,999);
Then pass the modified date objects as usual in your MongoDB aggregation pipeline in the $match operator:
var pipeline = [
{
"$match": {
"createdAt": { "$gte": start, "$lt": end }
}
},
{
"$group": {
"_id": null,
"count": { "$sum": 1 }
}
}
];
Model.aggregate(pipeline, function (err, result){
if (err) throw new Error();
console.log(JSON.stringify(result));
});
If you are using the momentjs library, this can be done by using the startOf() and endOf() methods on the moment's current date object, passing the string 'day' as arguments:
var start = moment().startOf('day'); // set to 12:00 am today
var end = moment().endOf('day'); // set to 23:59 pm today

Resources