To use the snapshot feature one must create or cause a snapshot. Snapshot is usually created by emitting it in the particular function.

snapshot event can be emitted using emit('snapshot',snapshot) from inside of your component function.

An example implementation could be something like this:

'use strict';

const elasticio = require('elasticio-node');
const messages = elasticio.messages;

exports.process = processTrigger;

function processTrigger(msg, cfg, snapshot) {
    console.log('Message %j', msg);
    console.log('Config %j', cfg);
    console.log('Snapshot %j', snapshot);

    snapshot.iteration = snapshot.iteration || 0;

    console.log('Iteration: %d', snapshot.iteration);

    snapshot.iteration += 1;

    this.emit('snapshot', snapshot);
    this.emit('data', messages.newMessageWithBody({iteration: snapshot.iteration}));
    this.emit('end');
}

This is a very basic example which practically iterates the number of times which snapshot is emitted and reports it on a console. It is perhaps not very much useful but this example already demonstrates how our platform expects the snapshot to be used as a parameter in the function.

Example from Outlook Component

For more specific example let us have a look at the trigger contacts.js function in outlook component.

/* eslint no-console: 0 no-invalid-this: 0*/
'use strict';
const messages = require('elasticio-node').messages;
const co = require('co');
const MicrosoftGraph = require('msgraph-sdk-javascript');
const rp = require('request-promise');

/**
 * This method will be called from elastic.io platform providing following data
 *
 * @param msg incoming message object that contains ``body`` with payload
 * @param cfg configuration that is account information and configuration field values
 * @param snapshot - snapshot that stores the data between the runs
 */
function processAction(msg, cfg, snapshot) {
    console.log('Snapshot is %j', snapshot);

    // Should be in ISO-Date format
    snapshot.lastModifiedDateTime = snapshot.lastModifiedDateTime || new Date(0).toISOString();

    // Main loop
    return co(function* mainLoop() {
        console.log('Refreshing an OAuth Token');
        const newToken = yield rp({
            method: 'POST',
            uri: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
            json: true,
            form: {
                refresh_token: cfg.oauth.refresh_token,
                scope: cfg.oauth.scope,
                grant_type: 'refresh_token',
                client_id: process.env.MSAPP_CLIENT_ID,
                client_secret: process.env.MSAPP_CLIENT_SECRET
            }
        });
        console.log('Updating token');
        this.emit('updateKeys', {
            oauth: newToken
        });

        const client = MicrosoftGraph.init({
            defaultVersion: 'v1.0',
            debugLogging: true,
            authProvider: (done) => {
                done(null, newToken.access_token);
            }
        });

        console.log('Selecting contacts that was modified since %s', snapshot.lastModifiedDateTime);
        const contacts = yield client
            .api('/me/contacts')
            .orderby('lastModifiedDateTime asc')
            .top(900)
            .filter('lastModifiedDateTime gt ' + snapshot.lastModifiedDateTime)
            .get();
        const values = contacts.value;
        console.log('Found %s contacts', values.length);
        if (values.length > 0) {
            const message = messages.newMessageWithBody({
                contacts: values
            });
            this.emit('data', message);
            let lmdate = new Date(values[values.length - 1].lastModifiedDateTime);
            // The output value has always 0 milliseconds
            // we need to set the milliseconds value to 999 in order not to see
            // the duplicate results
            lmdate.setMilliseconds(999);
            snapshot.lastModifiedDateTime = lmdate.toISOString();
        } else {
            console.log('No contacts modified since %s were found', snapshot.lastModifiedDateTime);
        }
        console.log('Processing completed, new lastModifiedDateTime is ' + snapshot.lastModifiedDateTime);
        this.emit('snapshot', snapshot);
    }.bind(this));
}

module.exports.process = processAction;

Let us go through the code and highlight the main areas where the snapshot is used. We define it in the main function processAction(msg, cfg, snapshot) on line 15. Then on lines 16-19 we initiate the snapshot and define what exactly should be stored in it, which is only the ISO-Date of access.

Lines 21-39 deal with the refresh_token and are initiated on every call in order to keep it current. This is specifically required by Microsoft. For more insides into the topic of OAuth access please consult our OAuth documentation.

Lines 41-47 define the specific client on Microsoft's side which would be enquired via API call.

On line 49 we print out via console.log what is the current value in the snapshot and inform that we will now attempt to enquire the new values added since the last access. Then the actual call to API is done starting from the line 50. values are filtered and fetched only the new ones since the last biggest change of the snapshot.lastModifiedDateTime on the line 54-55.

Now if there are new values, meaning the values.length > 0 then the last modification date lmdate is defined on line 63 and then written as a new snapshot value on line 68 snapshot.lastModifiedDateTime = lmdate.toISOString(); and then being informed about that on line 72.

If there are no new values then we are being informed about that via concole.log on line 70.

In the end, we emit the snapshot one more time on line 73. We do this in both cases. No matter if there are or there are no new values since our last access. This way we effectively overwrite it with the last current value.

Please note that in the end we overwrite the whole snapshot with the last value and this will happen every time. So again to highlight, a snapshot is not a storage but rather a useful piece of paper to record the last values to come back to it next time.