I recently switched from memcached to redis in nodejs. The thing I liked in node-memcached was that I can save the whole javascript object in the memory. Sadly I couldn't do this in redis. For example, I got the following object:
var obj = {
name: "Hello world!",
author: "admin",
user: {
"yolololo" : {
"id": "352asdsafaseww",
"server": 5,
"data" : {
x: 1,
y: 1,
z: 50
}
},
"yolol" : {
"id": "358dsa",
"server": 7
}
}
}
with the 3rd-Eden/node-memcached I could just do:
memcached.set("obj", obj, 12345, function(err) { });
and then
memcached.get("obj", function(err, data) {
console.log(data);
});
And I'll get the object I saved, just the way it is.
The problem with redis is that if I save the object like this:
redisclient.set("obj", obj, redis.print);
When I get the value with
redisclient.get("obj", function(err, data) {
console.log(data);
});
The output is just string containing [object Object].
Yeah I understand redis is text-based protocol and it's trying to do obj.toString(), but seems memcached take care of objects and redis don't.
I thought I could just do:
redisClient.set("obj", JSON.stringify(obj));
but I'm not sure if this will be good, because there will be insane high I/O and I'm not sure if the JSON obj->string will be bottleneck ( 10k+ request/second ).
Both Memcached and Redis store the data as string, but does redis have built-in feature for converting objects?
First of all redis only supports the following data types:
String
List
Set
Hash
Sorted set
You'll need to store objects as string in both redis and memcached.
node-memcached parses/stringifies the data automatically. But node-redis doesn't.
However, you can implement your own serialization/deserialization functions for your app.
The way node-memcached stringifies an object is as follows:
if (Buffer.isBuffer(value)) {
flag = FLAG_BINARY;
value = value.toString('binary');
} else if (valuetype === 'number') {
flag = FLAG_NUMERIC;
value = value.toString();
} else if (valuetype !== 'string') {
flag = FLAG_JSON;
value = JSON.stringify(value);
}
It also parses the retrieved text this way:
switch (flag) {
case FLAG_JSON:
dataSet = JSON.parse(dataSet);
break;
case FLAG_NUMERIC:
dataSet = +dataSet;
break;
case FLAG_BINARY:
tmp = new Buffer(dataSet.length);
tmp.write(dataSet, 0, 'binary');
dataSet = tmp;
break;
}
Related
I am using nodejs for the server.
Currently I have a Json in my project folder.
name.json
{
"name_English": "Apple",
"name_German": "Apfel",
"name_French": "Pomme"
}
When I send request to server, it returns:
GET http://localhost:3030/name
{
"name_English": "Apple",
"name_German": "Apfel",
"name_French": "Pomme"
}
But I found it is not convenient for frontend development.
Is there any way to do something like below?
GET http://localhost:3030/name?lang=en
{
"name": "Apple"
}
GET http://localhost:3030/name?lang=fr
{
"name": "Apfel"
}
Edit 1
The code of getting the Json in Feathers.js
name.class.js
const nameLists = require('../name.json')
exports.Test = class Test {
constructor (options) {
this.options = options || {};
}
async find (params) {
return nameLists
}
};
Edit 2
Is it possible to make name.json like this?
{
"name": ${name}
}
Edit 3
The reason I want to achieve above because I have to return whole Json file.
For the internationalization library, it seems needed to handle outside the JSON and I don't know what is the best practise to do so.
Here's a full demonstration with just express. (Hope that's ok.)
const express = require('express');
const app = express();
const port = 3030;
const nameLists = require('./name.json');
const unabbreviateLanguage = {
en: 'English',
de: 'German',
fr: 'French'
}
function filterByLanguage(obj, abbr) {
let language = unabbreviateLanguage[abbr];
let suffix = '_' + language;
let result = {};
for (let key in obj) {
if (key.endsWith(suffix)) {
let newkey = key.slice(0, -suffix.length);
result[newkey] = obj[key];
}
}
return result;
}
app.get('/name', (req, res) => {
res.json(filterByLanguage(nameLists, req.query.lang));
});
app.listen(port);
e.g.:
curl http://localhost:3030/name?lang=de
output:
{"name":"Apfel"}
The idea is to iterate over the keys of the input object and prepare an output object that only has keys that match the language suffix (then strip off that suffix). You'll likely want to either have a mapping of en -> English, or just use the key names that match the parameter e.g., rename name_English to name_en.
In FeathersJS, the params object of find will store the query string of the passed in URL. So if you call http://localhost:3030/name?lang=en, the params object will be :-
{
query: {
lang: 'en'
}
}
You can then use this information to determine which result from the JSON to return.
https://docs.feathersjs.com/guides/basics/services.html#service-methods
Your question appears to be two parts: handling queries, and handling the internationalization.
Handling the query:
Feathers presents queries through the context object at the following location:
context.params.query
Handling Internationalization:
There are many solid packages available for handling internationalization:
https://openbase.com/categories/js/best-nodejs-internationalization-libraries?orderBy=RECOMMENDED&
I have an array in JavaScript that I use JSON.stringify() on that ends up looking like this after:
[
{
"typeOfLoan":"Home"
},
{
"typeOfResidency":"Primary"
},
{
"downPayment":"5%"
},
{
"stage":"Just Looking"
},
{
"firstName":"Jared"
},
{
"lastName":"Example"
},
{
"email":"Jared#demo.com"
},
{
"cell":"8888888888"
},
{
"loanofficer":"Jim Loan"
}
]
I want the output to be a standard JSON object so that I can send it in a POST. Before this gets marked as duplicate, I have tried all of the answers I could possibly find already and they all end up not working or having syntax errors that I do not understand how to fix. This array is stored in variable jsonArray.
The array of objects, all with a single key, seems fishy. I suppose you want a single object literal with all the keys, which you can then send to you backend (and parse there). So first, reduce the many objects in a single one, then implement your ajax call to POST it to wherever. Here's how to reduce it:
let arr = [{"typeOfLoan":"Home"},{"typeOfResidency":"Primary"},{"downPayment":"5%"},{"stage":"Just Looking"},{"firstName":"Jared"},{"lastName":"Example"},{"email":"Jared#demo.com"},{"cell":"8888888888"},{"loanofficer":"Jim Loan"}];
let res = arr.reduce((a,b) => {
let key = Object.keys(b)[0];
a[key] = b[key];
return a;
}, {});
console.log(res);
Depending on what you use to send it to the backend, you might need to use JSON.stringify on res
Before stringifying, convert your request payload from an array to an object.
const arr = [{"typeOfLoan":"Home"},{"typeOfResidency":"Primary"},{"downPayment":"5%"},{"stage":"Just Looking"},{"firstName":"Jared"},{"lastName":"Example"},{"email":"Jared#demo.com"},{"cell":"8888888888"},{"loanofficer":"Jim Loan"}];
const payload = arr.reduce(function(acc, prev){
return Object.assign(acc, prev);
}, {});
console.log(payload);
I'm using npm module traverse to filter data coming from mongodb / mongoose.
I might get this data:
[ { rating: 5,
title: { da: 'Web udvikling', en: 'Web Development' } },
{ rating: 5, title: { da: 'Node.js', en: 'Node.js' } } ]
'da' and 'en' indicates languages. I use traverse to filter mongoose data after current language like this:
var filtered = filterLanguage(lang, results);
// filter json obj by language
var filterLanguage = function(language, obj) {
return traverse(obj).map(function (item) {
if (this.key === language) {
this.parent.update(item);
}
});
};
I then show this in my template:
res.render('index', {
skills: filtered.skills
});
Finally I display it in the jade view:
ul.list-group
each skill, i in skills
if i < 5
li.list-group-item.sidebar-list-item= skill.title
Unfortunately it's displayed with quotes:
<ul>
<li>'Web Development'</li>
<li>'Node.js'</li>
</ul>
These quotes are not there in the unfiltered data (results.skill.title.da). So traverse is adding them. I used the module with 'plain' json and it's working perfectly.
The mongoose data seems plain and simple but of course there are a lot of properties on the prototype. Also traverse stalls if I don't omit '_id' (type bson/objectid) property from result set.
So traverse seems to have problems with mongoose data... Why is this? And how can I fix it?
-- EDIT --
I found a solution:
Before filtering I do this:
var json = JSON.parse(JSON.stringify(results));
var filtered = filterLanguage(lang, json);
This removes the quotes, but I'm not sure exactly what it does. Somehow converting the mongoose result to JSON? An explanation would be highly appreciated.
Fields in Mongoose documents are getters/setters, which seem to confuse either traverse or Jade/Pug.
The shortest method I found that seems to fix all of your issues is pretty ugly:
var filtered = filterLanguage(lang, results.map(r => JSON.parse(JSON.stringify(r))));
A more elaborate version:
var filtered = filterLanguage(lang, results.map(r => {
let j = r.toJSON()
j._id = j._id.toString()
return j;
}));
It would have been helpful to see what is the body of filterLanguage exactly or understand why it's called twice but as it stands, I don't think you need to use the traverse package at all.
A function such as below should do the trick and I even expanded it to work if the data is more tree-like and not as flat as represented in your example.
const reduceByLang = (data, lang) => {
// Look for a `lang` key in obj or
// if not found but still an object, recurse
const reduceByLangObj = (obj) => {
Object.keys(obj).forEach((key) => {
if (obj[key] === null) {
return;
}
if (obj[key][lang]) {
obj[key] = obj[key][lang]; // replace with desired lang
} else if (typeof obj[key] === 'object') {
reduceByLangObj(obj[key]); // recurse
}
});
return obj;
};
if (Array.isArray(data)) {
return data.map(reduceByLangObj);
} else {
return reduceByLangObj(data);
}
};
See example in JS Bin.
Also, if possible at all and if you do this type of selecting very often, I would look into saving the data in a different structure:
{ ratings: x, locales: { en: { title: 'Y' }, { da: { title: 'Z' } } } }
maybe, so that you can pick the selected language easily either in the query itself and/or in the controller.
EDIT: Checking for null.
So what i'm trying to achieve is creating a json flat file to store user info where i'm stuck is that i don't know how to add new nested objects that are empty and then save the json file and reload it.
what i have in my *json* file is this.
{
"users" : {
"test" : {
},
"test1" : {
}
}
}
I'm trying to add as many new objects as i want to it. So for example.
{
"users" : {
"test" : {
},
"test1" : {
},
"test2" : {
},
"test3" : {
}
}
}
My server side Javascript
json.users.push = username;
fs.writeFile("./storage.json", JSON.stringify(json, null, 4) , 'utf-8');
delete require.cache[require.resolve('./storage.json')];
json = require("./storage.json");
With this code it does not write the file so when the require is done i end up with the same file and my json object ends up like this when i console.log it
{
"users": {
"test": {},
"test1": {},
"push": "test2"
}
}
Please do not recommend some external module to solve something has simple as this. Also if any one can point me to a in depth json documentation that gets straight to the point with what i'm try to do it would be appreciated
Use [] to access a dynamic key on the object
json.users[username] = {a: 1, b: 2}
Be careful naming your variable like that tho because json the way you're using it is not JSON. JSON is a string, not an object with keys.
See the below demo for distinction
var json = '{"users":{"test1":{},"test2":{}}}';
var obj = JSON.parse(json);
var newuser = 'test3';
obj.users[newuser] = {};
console.log(JSON.stringify(obj));
//=> {"users":{"test1":{},"test2":{},"test3":{}}}
This question already has answers here:
How to filter object array based on attributes?
(21 answers)
Closed 8 years ago.
I have seen very old answers to this question and many of the technologies used 2 years back have changed.
What I have is JSON files sent by a database over to my server, and what I would like to know is how to filter that data.
I am running a server with node.js, and what I would like to do is something like:
var results = QueryLibrary.load(jsondata);
var filtered = results.query('select where user = "user1"');
How can I do something like this in javascript running in node?
underscore has a where function that does just this
var _ = require("underscore");
var json = '[{"user": "a", "age": 20}, {"user": "b", "age": 30}, {"user": "c", "age": 40}]';
var users = JSON.parse(json);
var filtered = _.where(users, {user: "a"});
// => [{user: "a", age: 20}]
Another utility library, Lo-Dash, has a where function that operates identically.
You can add underscore to your project using
$ npm install --save underscore
or lodash
$ npm install --save lodash
If you only care about the where function, lodash offers it as a separate module
// only install lodash.where
$ npm install --save lodash.where
To use it in your project
var where = require("lodash.where");
// ...
var filtered = where(users, {"user": "a"});
Even if you use a library to do this, a better approach is probably to setup a chain of streams that handles all of your data processing in smaller modules.
Without knowing what you actually want to do, I've created this as an example. For the purposes of this code, maybe think of a debug logging stream or something.
json-parser.js
input: string (JSON)
output: object
var Transform = require("stream").Transform;
function JsonParser() {
Transform.call(this, {objectMode: true});
this._transform = function _transform(json, enc, done) {
try {
this.push(JSON.parse(json));
}
catch (e) {
return done(e);
}
done();
}
}
JsonParser.prototype = Object.create(Transform.prototype, {
constructor: {
value: JsonParser
}
});
module.exports = JsonParser;
obj-filter.js
input: object
output: object (result of where(data, filters))
var Transform = require("stream").Transform;
var where = require("lodash.where");
function ObjFilter(filters) {
Transform.call(this, {objectMode: true});
this._transform = function _transform(obj, enc, done) {
this.push(where(obj, filters));
done();
}
}
ObjFilter.prototype = Object.create(Transform.prototype, {
constructor: {
value: ObjFilter
}
});
module.exports = ObjFilter;
stringifier.js
input: object
output: string (JSON)
var Transform = require("stream").Transform;
function Stringifier() {
Transform.call(this, {objectMode: true});
this._transform = function _transform(obj, enc, done) {
this.push(JSON.stringify(obj));
done();
}
}
Stringifier.prototype = Object.create(Transform.prototype, {
constructor: {
value: Stringifier
}
});
module.exports = Stringifier;
app.js
// modules
var JsonParser = require("json-parser");
var ObjFilter = require("obj-filter");
var Stringifier = require("stringifier");
// run
var parser = new JsonParser();
// setup stream chain
parser.pipe(new ObjFilter({"user": "a"}))
.pipe(new Stringifier())
.pipe(process.stdout);
// send example json in
parser.write('[{"user": "a", "age": 20}, {"user": "b", "age": 30}, {"user": "c", "age": 40}]');
// output
// => [{"user":"a","age":20}]
Here, I made a Stringifier stream that converts objects back into JSON so that we can see them dumped into the console, though you could easily create any streams you needed to handle the operations that your app requires. Your stream end points will likely not end up in writing to the console.
As a last note, you would probably create a database stream that accepts some sort of query options and emits json. You would pipe that stream directly into parser.
Anyway, I hope this gives you a better idea of how to process data in node.js.
You can use any of the normal array/object built-in functions that javascript has, normally that kind of query would be made at the time of retrieving your data from the database, not after.
something like
for(i=0;i<objIdsArray.length;i++) {
for(j=0;j<mockJSON.length;j++) {
if(mockJSON[j]["id"] === parseInt(objIdsArray[i])) {
mockJSON.splice(j, 1); // to delete it, could be any other instruction
}
}
}