I am running a Node JS app (Sails JS, but shouldn't matter) and MongoDB (also shouldn't matter).
I have a database model that the WebApp saves many instances of it. For simplicity, let us take a UserActivityHistory model example (the example is not my real case, so nevermind the logic).
One of the members of the model is "ActivityType", which can be a medium-long text but can be chosen from a static set. For example:
So, assume that I am going to save thousands of instances, I prefer to save activity type identifier/code for memory performance. For example:
Instead of saving "User added a new account", the WebApp should save "UANC".
When the user wants to view the "UserActivityHistory", I want to have a static mapper (maybe global variable?) that is some kind of dictionary as follows:
Which means, I receive the code of the activity and returns the text from a static dictionary that is saved in the server memory running the application.
What is the most efficient way and best practices to achieve this mapping?
The ways I thought of:
1) Global variables: saving a global dictionary and add/remove values from it by API calls. I am not sure if this is a wise idea, I still do not see why not, but still deep in my heart something is telling me do not trust global variables.
2) Saving mappers in another database: this requires another call to the database for each set of activities. (doesn't seem so heavy to me, if I load many activities at once, but still there could be a better solution).
If you want to avoid having to redeploy your app everytime a string changes then I would recommend you look at pulling these from some persistant storage (e.g. external file / DB).
Regardless of which you choose, given they are application settings, you would pull them once either as the app starts or on first access. This would give you the flexibility of changing them out-with the app (or perhaps even from the app).
To answer your comments
If I pull them as the app starts on first access, where should I save them? global variable?
Well the natural thing to do here would be to have it as it's own module, this would give you a good place to have other methods for manipulating the list & persisting to storage. If you go for the singleton approach then you could load the resource on first access e.g.
ActivityType.js
var fs = require('fs');
var cache = null;
function loadCache(callback) {
if (!cache) {
fs.readFile('/path-to-strings', function (err, data) {
if (!err) {
// for the purpose of the example, lets assume you are storing the
// strings as a JSON object e.g. { 'key1': 'value1', 'key2': 'value2' }
cache = JSON.parse(data);
callback(null, cache);
} else {
callback(err, null);
}
});
} else {
callback(null, cache);
}
};
module.exports = {
get: function(key, callback) {
loadCache(function(err, cache) {
callback(err, (cache || {})[key]);
});
},
add: function(key, value, callback) {
loadCache(function(err, cache) {
if (err) {
if (callback) callback(err);
} else {
cache[key] = value;
}
});
},
remove: function(key, callback) {
loadCache(function(err, cache) {
if (err) {
if (callback) callback(err);
} else {
delete cache[key];
}
});
},
save: function(callback) {
loadCache(function(err, cache) {
if (err) {
if (callback) callback(err);
} else {
var data = JSON.stringify(cache, null, 4); // save formatted for easier editing
fs.writeFile('/path-to-strings', data, callback);
}
});
}
};
App.js
var ActivityType = require('./ActivityType');
...
ActivityType.get('UNAC', function(err, text) {
if (!err) {
console.log(text);
} else {
console.log('Unable to load string');
}
});
ActivityType.add('UCAP', 'User changed account password');
ActivityType.remove('UNAC');
ActivityType.save(function(err) {
if (!err) {
console.log('Saved successfully!');
} else {
console.log('Unable to save strings');
}
});
Alternatively, you could have an explicit load or init method you could call during app startup.
How expensive is the redeployment of the app?
That's not something I could answer as there is not enough information here, only you know how expensive a redeployment of your app would be. Regardless, surely updating a DB record or changing a resource file is far simpler than a redeployment?