Node function runs multiple times inside Mongoose query - node.js

I'm creating an Agenda function (similar to a cron job) to email us a list of new users every night. I think maybe I don't understand how the data is returned from the Mongoose call as I seem to be getting duplicate emails by the same number of results are returned from the Mongoose query. (Postmark is an email api here)
Here's a trimmed down version of my code:
var Agenda = require('agenda');
var agenda = new Agenda({db: { address: 'mongodb://localhost/example }});
var User = mongoose.model('User', userSchema);
agenda.define('example email', function() {
User.find({ date: { $gt: date }}, function (err, users) {
if (err) // handle error
postmark.send({
// setup and send email with users listed in body
}, function(error, success) {
if (error) // handle error
console.log('Sent successfully');
});
});
// Run every day at 2am
agenda.every('* 2 * * *', 'example email');
agenda.start();
So firstly the email sends straight away as I run the server (this code is in app.js) - I'm not sure why that is. But the main issue is that I receive multiple emails - they were received exactly 10 minutes apart, whether that is of any relevance. So for example the DB query returned 4 users so I received 4 emails of exactly the same data.
Do I need to close the query or something? I'm not looping through labels before sending the email - I thought that model.find() would just return one array of labels? But seems to be returning the same data each time for every label in labels. Going mad here.
I've just tried it on my local machine and there isn't the same problem, but it's the exact same code. I've also checked the Agenda DB to make sure there isn't duplicate jobs.

Related

firebase functions date query

Im trying to run a cron job to delete old notifications. Following a post on this on medium:
https://medium.com/#varunpvp/how-to-schedule-a-firebase-cloud-function-ded2db0cf9f3
This is where im up to:
const oneMonthOld = admin.firestore.Timestamp.now().toMillis() - 2592000000;
const oldNotifications = await admin.firestore()
.collection('notifications')
.where('createdAt', '>', oneMonthOld);
I've created a document in this collection. I have other queries in the function working against this collection. The article sais that more than is < (?) i've tried both ways round
const results2 = await oldNotifications.get();
results2.forEach(doc => {
console.log('in function');
oldNotificationsBatch.delete(doc.ref);
});
the function neither deletes the record or emits the log in the UI
Can anyone suggested whats going wrong here?

Bot Framework Node.js ad hoc message TO A SPECIFIC USER

I have been staring at this for hours and can't find a solution and that is even though by all suggestions it SHOULD be quite easy - https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-proactive-messages.
I have created a simple code which will "register" the user and save their data in my cosmosDatabse on Azure. That works perfectly.
//ON "register" SAVE USER DATA AND SAY REGISTERED MESSAGE
bot.dialog('adhocDialog', function(session, args) {
var savedAddress = session.message.address;
session.userData.savedAddress = savedAddress;
//REGISTERED MESSAGE
session.endDialog("*Congratulations! You are now registered in our network! (goldmedal)*");
})
.triggerAction({
matches: /^register$/i
})
But how can I then access that specific user and send him a message if, say, a condition is met? (in fact on HTTP request)
I am fairly certain we have to write the conversation ID or user ID somewhere. The question is where?
function startProactiveDialog(address) {
bot.beginDialog(address, "A notification!");
}
This is how simple I think it should be. But where do you specify the user then?
You've saved the address of the user inside of your database by saving it to session.userData.savedAddress. When the event triggers, perform a query to your database that checks for the users that meet two criteria.
They're registered to listen for the event
Their address has been saved inside of the database.
In your case, you can save a property to the session.userData object, a property that lists which events they're listening for. If you just need to send a message to the user, then you can simply use bot.loadSession(savedAddress) to ping the user.
Edit:
So instead of looking specifically by user ID, you should send a query to your CosmosDB that looks for entries that have a "listen-to" Boolean-type flag corresponding to the event.
You're not worrying about the user ID at first, you're just retrieving all entries with a query that would (broadly speaking) look like this:
SELECT * FROM BotState WHERE data LIKE 'listenForEvent=1.
So to setup your session.userData so that the above theoretical query would work, you would need to modify that snippet of code in your question to something like the following:
bot.dialog('adhocDialog', function(session, args) {
var savedAddress = session.message.address;
session.userData.savedAddress = savedAddress;
session.userData.listenForEvent = 1 // Our property we're going to look for.
session.endDialog("*Congratulations! You are now registered in our network! (goldmedal)*");
})
.triggerAction({
matches: /^register$/i
})
Actually, the savedAddress should be an instance of IAddress, and also, the function loadSession(address: IAddress, callback: (err: Error, session: Session) => void): void; and address(adr: IAddress): Message; under Message class all require IAddress as the parameter.
So first of all, you should save the entire address json object in cosmosDB for later using.
As botbuilder for Node.js is built on Restify or Express, you can build an addition route for your user to trigger and send proactive messages. The work flow could be following:
Guide user to register & Save the user's address object with the account mapping in your DB
Create a Route in Restify or Expressjs for trigger the proactive message:
server.get('/api/CustomWebApi', (req, res, next) => {
//find the user's address in your DB as `savedAddress`
var msg = new builder.Message().address(savedAddress);
msg.text('Hello, this is a notification');
bot.send(msg);
res.send('triggered');
next();
}
);
or if you want to leverage loadSession
server.get('/api/CustomWebApi', function (req, res, next) {
bot.loadSession(savedAddress, (err, session) => {
if (!err) {
session.send('Hello, this is a notification')
session.endConversation();
}
})
res.send('triggered');
next();
});
I created a users.json file, to which I save all the users. It works the way I need it to. I guess database would be better, but I don't really have a clue where to begin with that. Database is a whole new chapter I have not encountered yet, so it doesn't make sense to work on it when the project needs are resolved.

A possible timeout in find() method - mongoDb

I'm writing a Node.js project using MongoDb and socket.io. I met one problem. I have a collection called rooms rooms = db.collection('rooms');
Here's my code when i'm trying to join a room
rooms.find({name: roomName}).limit(1).toArray()
.then(function (res) { //if successful
res = res[0]; //i get my username
If there's a room with the given id I connect to it, otherwise it must be created.
But when i create a new room i get undefined, but when I connect the second time (the room already exists) it's all ok, i get all the information. So when I create a room and connect to it, I don't get my username, but when it's created (I'm connecting to it the second time) it displays me the method.
var mongo = require('mongodb').MongoClient - module,
function http(io) { mongo.connect(config.mongodb_url)
.then(function (db) { ...
-connection,
"mongodb version": "^2.1.7"
This is how i create a room
rooms.findOneAndUpdate(
{name: roomName},
{$addToSet: {users: uuid}}
).then(users_update).catch(logger.error);
}).catch(logger.error);
I'm wondering if there are some timeout in the find method? Or where can be here the mistake?
I found the answer. It was just that simple: I added { upstream: true } to my findOneAndUpdate() function.

how to publish a page using node.js

I have just begun to learn node.js. Over the last two days, I've been working on a project that accepts userinput and publishes a ICS file. I have all of that working. Now consider when I have to show this data. I get a router.get to see if I am at the /cal page and..
router.get('/cal', function(req, res, next)
{
var db = req.db;
var ical = new icalendar.iCalendar();
db.find({
evauthor: 'mykey'
}, function(err, docs) {
docs.forEach(function(obj) {
var event2 = ical.addComponent('VEVENT');
event2.setSummary(obj.evics.evtitle);
event2.setDate(new Date(obj.evics.evdatestart), new Date(obj.evics.evdateend));
event2.setLocation(obj.evics.evlocation)
//console.log(ical.toString());
});
});
res.send(ical.toString());
// res.render('index', {
// title: 'Cal View'
// })
})
So when /cal is requested, it loops through my db and creates an ICS calendar ical. If I do console.log(ical.toString) within the loop, it gives me a properly formatted calendar following the protocol.
However, I'd like to END the response with this. At the end I do a res.send just to see what gets published on the page. This is what gets published
BEGIN:VCALENDAR VERSION:2.0
PRODID:calendar//EN
END:VCALENDAR
Now the reason is pretty obvious. Its the nature of node.js. The response gets sent to the browser before the callback function finishes adding each individual VEVENT to the calendar object.
I have two related questions:
1) Whats the proper way to "wait" till the callback is done.
2) How
do I use res to send out a .ics dynamic link with
ical.toString() as the content. Do I need to create a new view for
this ?
edit: I guess for number 2 I'd have to set the HTTP headers like so
//set correct content-type-header
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: inline; filename=calendar.ics');
but how do I do this when using views.
Simply send the response, once you got the neccessary data! You are not required to end or send directly in your route but can do it in a nested callback as well:
router.get('/cal', function(req, res, next) {
var db = req.db;
var ical = new icalendar.iCalendar();
db.find({
evauthor: 'mykey'
}, function(err, docs) {
docs.forEach(function(obj) {
var event2 = ical.addComponent('VEVENT');
event2.setSummary(obj.evics.evtitle);
event2.setDate(new Date(obj.evics.evdatestart), new Date(obj.evics.evdateend));
event2.setLocation(obj.evics.evlocation)
});
res.type('ics');
res.send(ical.toString());
});
});
I also included sending the proper Content-Type by using res.type.
Also: Don't forget to add proper error handling. You can for example use res.sendStatus(500) if an error occured while retrieving the documents.

Inserting data to MongoDB - no error, no insert

I'm currently trying to make a register form using mongoDB and nodeJS - I've created new database and collection - I want to store: username, password, email and insert_time in my database.
I've added unique indexes to username/email and checked if it works - and I can not add a duplicated entry using mongo's console or rockmongo (php mongodb manager) - so it works fine.
However - when the piece of code that is supposed to register a new account is being executed and makes an insert with the data that is already in database - it returns an object that contains all the data that was supposed to be added with a new, unique id. The point is - it should return an error that would say that entries can not be duplicated and insert failed - instead it returns the data back and gives it a new id. Data that already resides in database remains untouched - even the ID stays the same - it's not rewritten with the new one returned by script's insert.
So, the question is... what am I doing wrong? Or maybe everything is fine and database's insert should return data even if it's failed?...
I even tried defining indexes before executing indexes.
I tried inserting the data using mongoDB's default functions and mongoJS functions - the result is the same in both cases.
The code I'm trying to execute (for mongoJS):
var dbconn = require("mongojs").connect('127.0.0.1:27017/db', ['users']);
var register = function(everyone, params, callback)
{
// TODO: validation
dbconn.users.ensureIndex({username:1},{unique:true});
dbconn.users.ensureIndex({email:1},{unique:true});
dbconn.users.save(
{
username: params.username,
password: params.password,
email: params.email,
insert_time: Date.now()
},
function(error, saved)
{
if(error || !saved)
{
callback(false);
}
else
{
console.log(error);
console.log(saved);
callback(true);
}
});
}
For both cases - inserting new data and inserting duplicated data that doesn't modify database in any way - ERROR is null and SAVED is just a copy of data that is supposed to be inserted. Is there any way to check if insert was made or not - or do I have to check whether the data already exists in database or not manually before/after making an insert?
Mongo works that way. You should tell you want to get errors back, using the safe option when you issue the save command (as per default it uses the "fire and forget" method).
https://docs.mongodb.com/manual/reference/command/getLastError/
This looks to be basically the same problem as MongoDB unique index does not work -- but with the JavaScript API rather than Java. That is, saving without either specifying the "safe" flag or explicitly checking the last error value is unsafe--- the ID is generated client side and the command dispatched, but it might still fail (e.g. due to a unique index violation). You need to explicitly get the last error status.
http://www.mongodb.org/display/DOCS/dbshell+Reference#dbshellReference-ErrorChecking suggests db.getLastError() using the command shell, and I assume the node API is identical where they can possibly make it so.
Same problem solved, just forgot that its async insert and any nodes process.exit stops adding data
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('parse.txt')
});
lineReader.on('line', function (line) {
console.log(line)
db.insert(line,{w:1},function(e,d){ if (e) throw e })
});
// f this s, data are still adding when do close KUR WA MAC 2 days of my f life wasted
lineReader.on('close', function() {
// ----->>>>>> process.exit(); <<<<<----------
});

Resources