Node.js update db object on save event in another - node.js

What is the most convenient way to create/update object on saving changes to other? Imagine we have a model Client and we emit event on save.
clientSchema.post('save', function (client) {
process.emit('clientUpdate', client);
});
Then we can subscribe for that event like:
process.on('clientUpdate', function(client) {
//LOGIC GOES HERE
});
Let's assume we want now to update ClientProjection. Where you would locate the listener and how you would implement update logic for mongoDB(mongoose)- using model, by dao, etc.?

I believe that you can avoid emitting another event and just make the update within the post-save hook. For example:
clientSchema.post('save', function (client, next) {
ClientProjection.update( {/* Query Parameters */},
{/* Data to update */},
function(err, clientProjection) {
next()
}
});
In a post-save hook, if you want to call an async function, you'll need to add next as your second argument and invoke it in the callback when the async action is complete. See the Asynchronous Post Hooks section of the mongoose Middleware docs

Related

Why is my RxJS Observable completing right away?

I'm a bit new to RxJS and it is kicking my ass, so I hope someone can help!
I'm using RxJS(5) on my express server to handle behaviour where I have to save a bunch of Document objects and then email each of them to their recepients. The code in my documents/create endpoint looks like this:
// Each element in this stream is an array of `Document` model objects: [<Document>, <Document>, <Document>]
const saveDocs$ = Observable.fromPromise(Document.handleCreateBatch(docs, companyId, userId));
const saveThenEmailDocs$ = saveDocs$
.switchMap((docs) => sendInitialEmails$$(docs, user))
.do(x => {
// Here x is the `Document` model object
debugger;
});
// First saves all the docs, and then begins to email them all.
// The reason we want to save them all first is because, if an email fails,
// we can still ensure that the document is saved
saveThenEmailDocs$
.subscribe(
(doc) => {
// This never hits
},
(err) => {},
() => {
// This hits immediately.. Why though?
}
);
The sendInitialEmails$$ function returns an Observable and looks like this:
sendInitialEmails$$ (docs, fromUser) {
return Rx.Observable.create((observer) => {
// Emails each document to their recepients
docs.forEach((doc) => {
mailer.send({...}, (err) => {
if (err) {
observer.error(err);
} else {
observer.next(doc);
}
});
});
// When all the docs have finished sending, complete the
// stream
observer.complete();
});
});
The problem is that when I subscribe to saveThenEmailDocs$, my next handler is never called, and it goes straight to complete. I have no idea why... Inversely if I remove the observer.complete() call from sendInitialEmails$$, the next handler is called every time and the complete handler in subscribe is never called.
Why isn't the expected behaviour of next next complete happening, instead it's one or the other... Am I missing something?
I can only assume that mailer.send is an asynchronous call.
Your observer.complete() is called when all the asynchronous calls have been launched, but before any of them could complete.
In such cases I would either make an stream of observable values from the docs array rather than wrap it like this.
Or, if you would like to wrap it manually into an observable, I suggest you look into the library async and use
async.each(docs, function(doc, callback) {...}, function finalized(err){...})

How to save object immediately in MongoDB?

In my Node application I use the mongoose module.
I found out that after
model_name.create({...})
object is not created immediately but with some delay (buffer?).
How can I force to save this new object in this particular moment?
Mongoose inserts the value inmediatly.
The problem is that you are not using it´s callback. Try to code this way:
//There is the definition
Customer.create(YOURDATA, function (err, obj) {
if (err) {
//This will be executed if create is going bad.
return handleError(res, err);
}
//This code will be executed AFTER SAVE
console.log(obj._id):
return res.json(201, obj);
});
Callback functions will be automatically executed by mongoose after the CREATE function has been executed in BD.
In obj, you will receive the saved object from DB, and then you will be able to access its properties.
Anyway, there you have some documentation:
the mongoose docs about callbacks
Some docs about Async methods:
Hope it will solve you problem

Node.js Async Loop to Query Database

I'm new to node.js.
I'm building a loop to query a database with chat messages every 3 seconds to then send required new messages to required users.
This is the loop I have - but currently it only loops once:
// New Database Chat Messages Send
var newDBMessagesInterval = 3000; // 3 Seconds
(function newDBMessagesSchedule() {
setTimeout(function() {
async(function() {
console.log('async is done!');
newDBMessagesSchedule();
});
}, newDBMessagesInterval)
})();
function async() {
console.log('in async function....');
}
Do I need to return something from the async function for the loop to continue?
Also is this a good/bad way to do a loop - my intention is to put a DB SELECT into the async function and don't what the DB calls to overlap.
Also is this non-blocking?
thx
There is nothing magical about aynchronous functions. You have to call the callback to an asynchronous function at some point. For testing purposes you should change async to:
function async(callback) {
callback();
}
Yes, this is non-blocking.
However, from your comment, I see that you're doing this to send messages to sockets. This isn't a great way to do that. You should look into getting a "pub/sub" system, and having each server subscribe and publish their own messages. Redis is a good choice for this.

Mongoose - how to tap schema middleware into the 'init' event?

It is suggested in the Mongoose docs that I should be able to control the flow using middleware that plugs in to the "init" hook.
However, I have so far had success only with "save" and "validate".
When I do something like this, neither of these middleware ever get called:
MySchema.post( "init", function (next) { console.log("post init") });
MySchema.pre( "init", function (next) { console.log("pre init") });
Am I missing something?
It turns out that the "init" event/hook is not fired when creating a new Model, it is only fired, when loading an existing model from the database. It seems that I should use the pre/validate hook instead.
I have successfully used middleware like MySchema.post('init', function() { ... }); with Mongoose which is then executed for each model instance loaded in a find query. Note that there isn't a next parameter to call with this middleware, it should just return when done.

Updating Mongo document from Node

so I am inserting a document into mongo db as such
io.sockets.on('connection', function (socket) {
connectLog(socket.handshake.address.address);
function connectLog(ipAddress) {
db.collection('tracking', function (err, collection) {
var currentTime = new Date();
var doc={"ip":ipAddress, "connect": currentTime, "culture": "en" };
collection.insert(doc, function () { });
});
}
I have another event
function logout(id, disconnect) {
I'd like to update (or replace?) that record and add disconnect: (time) to it. How would I go about doing this? This way I can tell when a person connects and when they disconnect from the chat.
I am using socket.io so I'll know their exact disconnect time
Thank you in advance
First, read this about explicit vs. implicit disconnects: Socket.io: How to handle closing connections?. Basically, your handler for explicit logouts (which are good!) should call the same code as your disconnect handler, in case the user doesn't get a chance to explicitly logout.
So in addition to your logout code, you'll also want:
socket.on('disconnect', handleDisconnect)
And in that disconnect/logout handler, you'll want to find the most recent connection document for that user and update it.
collection.findAndModify(
{"address" : address}, //same address
[['connect', 'descending']], //the most recent, findAndModify only changes the first doc
{$set: {disconnect: currentTime}}, //set the disconnect time
function(err, object){/*deal with errors*/}
)

Resources