adding JSON as property - json

I have a JSON object that looks like this:
{
"field": "value",
"field2": "value",
"field3": "value"
}
How can I add this to a keen event as a property similar to the "keen" object so I can reference individual fields, ie. my_property.field1

The properties on your events in Keen are based on whatever JSON you send in when you first post your event. You can post historical events, but you can't add new properties to events you've already posted. Here's an example of sending an event in JavaScript. Say your event is a tweet.
var client = new Keen({
projectId: 'PROJECT_ID',
writeKey: 'WRITE_KEY'
});
var tweet_event = {
keen: {
timestamp: new Date().toISOString(), // time the tweet happened
},
field: "value", // values you mentioned
field2: "value",
field3: "value,
tweet: { // other properties you might have
author: "#michellewetzler",
text: "Dwell on the beauty of life. Watch the stars, and see yourself running with them. (Marcus Aurelius)"
}
}
// Record the event (send it to Keen IO)
client.recordEvent('tweets', tweet_event, function(err, res){ // name your collection here
if (err) {
document.getElementById('yeah').innerHTML = "Something is amiss. Check console for errors. Did you forget a comma perhaps? Or a curly brace?"
}
else {
document.getElementById('yeah').innerHTML = "You just sent an event to Keen IO!"
}
});
then you can reference these properties in queries like:
var client = new Keen({
projectId: "PROJECT_ID",
readKey: "READ_KEY"
});
// count the number of tweets where field = value
var count = new Keen.Query("count", {
event_collection: "tweets",
timeframe: "this_14_days",
filters: [
{
property_name: "field",
operator: "eq",
property_value: value
}
]
});
// Send query
client.run(count, function(err, response){
// if (err) handle the error
console.log('result is: ', response.result);
});

Related

How to access the contents of a JSON file without a key?

Basically, I am setting up a web server via Node.js and Express (I am a beginner at this) to retrieve data by reading a JSON file.
For example, this is my data.json file:
[{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
I am trying to retrieve all of the colors by implementing this code for it to display on localhost:
router.get('/colors', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
res.json(data); //this displays all of the contents of data.json
})
});
router.get('/colors:name', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
for (var i = 0; i < data.length; i++) {
res.json(data[i][1]); //trying to display the values of color
}
})
});
How do I go about doing this?
What you are trying to do is actually pretty simple once you break it into smaller problems. Here is one way to break it down:
Load your JSON data into memory for use by your API.
Define an API route which extracts only the colours from your JSON data and sends them to the client as a JSON.
var data = [];
try {
data = JSON.parse(fs.readFileSync('/path/to/json'));
} catch (e) {
// Handle JSON parse error or file not exists error etc
data = [{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
}
router.get('/colors', function (req, res, next) {
var colors = data.map(function (item) {
return item.color
}); // This will look look like: ["black","red"]
res.json(colors); // Send your array as a JSON array to the client calling this API
})
Some improvements in this method:
The file is read only once synchronously when the application is started and the data is cached in memory for future use.
Using Array.prototype.map Docs to extract an array of colors from the object.
Note:
You can structure the array of colors however you like and send it down as a JSON in that structure.
Examples:
var colors = data.map(function(item){return {color:item.color};}); // [{"color":"black"},{"color":"red"}]
var colors = {colors: data.map(function(item){return item.color;})} // { "colors" : ["black" ,"red"] }
Some gotchas in your code:
You are using res.json in a for loop which is incorrect as the response should only be sent once. Ideally, you would build the JS object in the structure you need by iterating over your data and send the completed object once with res.json (which I'm guessing internally JSON.stringifys the object and sends it as a response after setting the correct headers)
Reading files is an expensive operation. If you can afford to read it once and cache that data in memory, it would be efficient (Provided your data is not prohibitively large - in which case using files to store info might be inefficient to begin with)
in express, you can do in this way
router.get('/colors/:name', (req, res) => {
const key = req.params.name
const content = fs.readFileSync(__dirname + '/data.json', 'utf8')
const data = JSON.parse(content)
const values = data.reduce((values, value) => {
values.push(value[key])
return values
}, [])
// values => ['black', 'red']
res.send(values)
});
and then curl http://localhost/colors/color,
you can get ['black', 'red']
What you're looking to do is:
res.json(data[i]['color']);
If you don't really want to use the keys in the json you may want to use the Object.values function.
...
data = JSON.parse(data)
var values = []
for (var i = 0; i < data.length; i++) {
values.push(Object.values(data[i])[0]) // 0 - color, 1 - category, 2 - type
}
res.json(values) // ["black","red"]
...
You should never use fs.readFileSync in production. Any sync function will block the event loop until the execution is complete hence delaying everything afterwords (use with caution if deemed necessary). A few days back I had the worst experience myself and learnt that in a hard way.
In express you can define a route with param or query and use that to map the contents inside fs.readFile callback function.
/**
* get color by name
*
* #param {String} name name of the color
* #return {Array} array of the color data matching param
*/
router.get('/colors/:name', (req, res) => {
const color = req.params.name
const filename = __dirname + '/data.json';
fs.readFile('/etc/passwd', 'utf8', (err, data) => {
if(err){
return res.send([]); // handle any error returned by readFile function here
}
try{
data = JSON.parse(data); // parse the JSON string to array
let filtered = []; // initialise empty array
if(data.length > 0){ // we got an ARRAY of objects, right? make your check here for the array or else any map, filter, reduce, forEach function will break the app
filtered = data.filter((obj) => {
return obj.color === color; // return the object if the condition is true
});
}
return res.send(filtered); // send the response
}
catch(e){
return res.send([]); // handle any error returned from JSON.parse function here
}
});
});
To summarise, use fs.readFile asynchronous function so that the event loop is not clogged up. Inside the callback parse through the content and then return the response. return is really important or else you might end up getting Error: Can't set headers after they are sent
DISCLAIMER This code above is untested but should work. This is just to demonstrate the idea.
I think you can’t access JSON without key. You can use Foreach loop for(var name : object){} check about foreach it may help you

Backbone: fetching from URL in router gets undefined, but it works when collection gets JSON from a variable

From a JSON stored in a variable I can get the name of the current id from a router function called show: function(id). However, when I fetch collection from an URL instead of using a JSON variable I get an undefined TypeError.
console.log(this.collection.get(id).get('name'));
What I have seen is that when I use a JSON variable the show function works fine, but when I fetch from URL, show function executes after fetch succeed.
What I am doing wrong? Why fetching from URL gets undefined? How can I make it work?
The following code is fictional, it only shows the relevant part of my code. See the two cases at the end of the code block.
jsFiddle here
// Data 1 with variable
var heroes = [
{"id": "1", "name": "Batman"},
{"id": "2", "name": "Superman"},
];
// Data 2 from url: http://example.com/heroes.json
[
{"id": "1", "name": "Batman"},
{"id": "2", "name": "Superman"},
];
HeroesCollection = Backbone.Collection.extend({
model: HeroesModel,
url: 'http://example.com/heroes.json'
});
HeroesRouter = Backbone.Router.extend({
// I use two shows to graphic this example
routes: {
'': 'index',
':id': 'show'
},
initialize: function(options) {
this.collection = options.collection;
this.collection.fetch();
// this.collection.fetch({async:false}); this fixes my problem, but I heard it is a bad practice
},
index: function() {
},
show: function(id) {
console.log(this.collection.get(id).get('name'));
// Case #1: When Collection loads from a Variable
// id 1 returns: 'Batman'
// Case #2: When Collection fetchs from URL, id 1 returns:
// TypeError: this.collection.get(...) is undefined
}
});
// Case #1: collection loads JSON from a variable
var heroesCollection = new HeroesCollection(heroes);
// Case #2: collection loads JSON with fetch in router's initialize
// var heroesCollection = new HeroesCollection();
var heroesRouter = new HeroesRouter({collection: heroesCollection});
How about this? It's been awhile, but this seems like a better approach to what you are trying to achieve. The basic concept is that once you navigate to your show route, it will execute show. This method will create a new, empty collection, and then fetch the data for it. Along with that, we pass in a success method (as François illustrated) which will execute when the request is finished with the JSON (which creates a collection of Heros).
I believe the reason you were running into the issue with the remote data is that you were trying to access this.collection before it was populated with data from the request.
You have to remember the request is asynchronous, which mean code execution continues while the request is processing.
HeroesCollection = Backbone.Collection.extend({
model: HeroesModel,
url: 'http://example.com/heroes.json'
});
HeroesRouter = Backbone.Router.extend({
routes: {
'': 'index',
':id': 'show'
},
index: function() {
},
show: function(id) {
this.herosCollection = new HerosCollection();
this.herosCollection.fetch({
success: function(collection, response, options) {
console.log(this.get(id).get('name'));
}
});
}
});
you need to trigger the router 'show' function when the collection has ended to load.
this.collection.fetch({async:false}); fixes your problem because the whole javascript code is waiting (async:false) the ajax call to be ended before going further.
The other and best solution is to wait that your collection is fetched before you try to use the results.
Basically:
MyCollection.fetch({
success: function(model, reponse) {
// do wtv you want with the result here or trigger router show method...
}
});

Backbone.js updating a Collection's model in the collection

I am having a bit of trouble organising the JSON I pass in into Backbone models as months (I am getting an empty collection). I am trying to be explicit as possible so the Year Collection is actually setting each of its parameters like so.
So I have a Backbone collection called Year which is a collection of Backbone models Month which in turn has an events attribute which is a collection of the model Event.
$(function(){
var Event = Backbone.Model.extend({
});
var Events = Backbone.Collection.extend ({
model: Event
});
var Month = Backbone.Model.extend ({
});
var Year = Backbone.Collection.extend ({
model: Month,
url: '/api/v1/calendar/2014'
});
window.Calendar = new Year();
var promise = Calendar.fetch();
promise.done(function(response){
if ('events' in response) {
console.log('Events found');
response = response.events;
// Cycle through events and add to Collection
for (var i = 0; i < response.length; i++) {
var currentMonth = response[i].startdate.split('-');
thisEvent = new Event(response[i]);
thisMonth = new Month({
'name': currentMonth[1],
'events': new Events(thisEvent)
});
Calendar.add(thisMonth);
console.log('Set ' + currentMonth[1] + ' with Event ' + response[i]);
}
} else {
console.error('Zero events');
}
}).fail(function(response){
console.error('Failed to fetch Calendar');
});
});
The JSON I pass in is very simple, something like this
{
"status": "success",
"year": 2014,
"events": [
{
"title": "None",
"startdate": "2014-01-23",
"description": "Event Description"
},
{
"title": "None",
"startdate": "2014-01-25",
"description": "Event Description 2"
}
]
}
I am not quite sure why I get an empty collection. The thing I am least certain about is setting the Month model with new Events(response[i]). Ideally I would initialize the events key with a new Events and then add response[i] to it.
Any help would be greatly appreciated,
Thank you
I do it this way usually:
var promise = calendar.fetch();
promise.done(function(response){
//This is where you process the collection that is returned from the server.
}).fail(function(response){
//In case of failure
});
I think all you need to do here is override the Collections parse function and do something like this:
parse: function(response) {
this.status = response.status;
this.year = response.year;
return response.events;
}
parse function should always return an array from which collection is populated.
Hope this helps.

create dijit accordian container from foreach loop with data returned from json

how do i use a for each loop to create accordian containers for each data returned from json file using ajax ?
i have tried this ! is it the way to it ?
dojo.xhrGet({
url:"json/"file_Name".json",
handleAs: "json",
timeout: 10000,
load: function(response,details){
container(response)},
error: function(error_msg,details){
container(error_msg, details);
}
});
//how do i use the json file to add data to the array arrFruit and then create dijit accordian container for every data in the array//
container = function(array, domConstruct) {
var arrFruit = ["apples", "kiwis", "pineapples"];
array.forEach(arrFruit, function(item, i){
domConstruct.create("li", {innerHTML: i+1+". "+item}, "properties");
});
};
//the response data from my json file is:-
[
{
"itemId": 1234,
"Name": "Name",
}]
I would suggest you re-write it into leveraging the ItemFileReadStore. The Store is a data container in which you can pull out items by their id. This means that your json needs to be changed slightly with description of what is identifier and - if any - which is the children attribute keys.
JSON:
{
identifier: 'itemId',
// you dont seem to have child references any but these are defaults
childrenAttrs: ['items', 'children'],
items: [
{
itemId: 1234,
name: 'Name'
}, {
...
}
]
}
then in your code, instead of using .xhr use .fetch in a store like so:
// 1.7+ syntax, pulling in dependencies.
// We want accordion and some other display widget like contentpane.
// Also we await domReady before calling our function
require(["dojo/data/ItemFileReadStore", "dijit/layout/AccordionContainer", "dijit/layout/ContentPane", "dojo/domReady!"], function(itemStore, accordion, contenpane) {
// this section is called when loading of itemstore dependencies are done
// create store
var store = new itemStore({
url:"json/"file_Name".json"
});
// create container
var acc = new accordion({style:"height: 300px"}, 'someDomNodeId');
// call XHR via .fetch and assign onComplete (opposed to 'load') callback
store.fetch({ onComplete: function(items) {
// items is an array of all the objects kept in jsonObject.items array
items.forEach(function(item) {
acc.addChild(new contentpane({
title: "Name for id: " + store.getValue(item, 'itemId'),
content: store.getValue(item, 'name')
}));
});
console.log(acc.getChildren()); // << would print out an array of contentpane widgets
});
});
This is howto :)
At any given time you could use the store and fetch some items, lets say you want to filter out some specific ones, call .query like so: store.fetch({query: { name: '*foo'/*all item.name ending with foo*/ }, onComplete: function(items) { /*cb func*/});
See
http://livedocs.dojotoolkit.org/dijit/layout/AccordionContainer#programmatic-example
and
http://livedocs.dojotoolkit.org/dojo/data/ItemFileReadStore

extjs store error handling

I am trying to handle an exception in an Ext.data.Store instance when creating a new Ext.data.Record. When the server responds with the following json:
{"success": false, "message": "some text"}
I get an exception of type 'request', even though the server returns an HTTP 200 Response!
To get a 'remote' error I have to create an object with the root property
({
"success": false,
"message": "some text",
"data": {
"PositionId": "00000000-0000-0000-0000-000000000000",
"Name": "123"
}
})
...but I don't want this. Is there any way to change this behaviour?
Also, when I insert a record in the store, it is automatically added to the associated grid, but if an error occurs it remains there, so I need to reload store on every error. Is there any better way to do this?
You should catch one of the two Store events:
loadexception (deprecated)
exception
For example you could:
// make the store
var myStore = new Ext.data.Store({...});
// catch loading exceptions
myStore.on('exception',function( store, records, options ){
// do something about the record exception
},this);
// load store
myStore.load();
You could also just use the success and failure events from the store to take action based on the success flag.
Finally, I've found out that if I send back empty data it works as expected. So I don't need to send back any fictional data, my server response is:
({
"success": false,
"message": "some text",
"data": {}
})
when success is false operation doesn't have a response property. This thread explains it very clairly!
http://www.sencha.com/forum/showthread.php?196013-access-operation.response-when-success-false
Example:
Ext.define("SC.store.SegurosCancelacionStore", {
extend: "Ext.data.Store",
model: "SC.model.PersonaSeguro",
proxy: {
timeout: 90000,
actionMethods: {
read : 'POST'
},
type: "ajax",
url: "../SegurosFinsolCancelacionServlet",
reader: {
type: "json",
root: "seguros",
messageProperty : 'msjError' //without this, it doesn't work
}
},
autoLoad: false
});
Implementation:
storeSegurosCancelacion.load({
params: {
'sucursal':sucursal,
'persona': persona
},
callback:function(records, operation, success){
msg.hide();
if(success == true){
if(records.length == 0){
Ext.Msg.alert('Resultado', 'No se ha encontrado información');
}
}
if(success == false){
try{
Ext.Msg.alert('Error', operation.getError()); // way more elegant than ussing rawData etc ...
}catch(e){
Ext.Msg.alert('Error', 'Error inesperado en el servidor.');
}
}
}
});
Best regards
#code4jhon