Parsing doubly nested JSON object to MongoDB - json

Schema for my MongoDB model:
var resultsSchema = new mongoose.Schema({
start_date: String,
end_date: String,
matches:[{
id:Number,
match_date:String,
status:String,
timer:Number,
time:String,
hometeam_id:Number,
hometeam_name:String,
hometeam_score:Number,
awayteam_id:Number,
awayteam_name:String,
awayteam_score:Number,
ht_score:String,
ft_score:String,
et_score:String,
match_events:[{
id:Number,
type:String,
minute:Number,
team:String,
player_name:String,
player_id:Number,
result:String
}]
}]
});
Example of JSON data coming from the server:
"matches":
[
{
"match_id":"1234"
"match_date":"Aug 30"
...
...
"match_events":
[
{
"event_id":"234",
"event_minute":"38",
...,
...
},
{
"event_id":"2334",
"event_minute":"40",
...,
...
}
],
{
"match_id":"454222"
"match_date":"Aug 3"
...
...
"match_events":
[
{
"event_id":"234",
"event_minute":"38",
...,
...
},
....
My current implementation works for parsing just the matches (i.e the first array). But I can't seem to access the inner array properly.
async.waterfall([
function(callback) {
request.get('http://football-api.com/api/?Action=fixtures&APIKey=' + apiKey + '&comp_id=' + compId +
'&&from_date=' + lastWeek_string + '&&to_date=' + today_string, function(error, response, body) {
if (error) return next(error);
var parsedJSON = JSON.parse(body);
var matches = parsedJSON.matches;
var events = parsedJSON.matches.match_events;
var results = new Results({
start_date: lastWeek_string,
end_date: today_string,
matches:[]
});
_.each(matches, function(match) {
results.matches.push({
id: match.match_id,
match_date: match.match_formatted_date,
status:match.match_status,
timer:match.match_timer,
hometeam_id:match.match_localteam_id,
hometeam_name:match.match_localteam_name,
hometeam_score:match.match_localteam_score,
awayteam_id:match.match_visitorteam_id,
awayteam_name:match.match_visitorteam_name,
awayteam_score:match.match_visitorteam_score,
ht_score:match.match_ht_score,
ft_score:match.match_ft_score,
et_score:match.match_et_score,
match_events:[]
});
});
_.each(events, function(event) {
results.matches.match_events.push({
id:event.event_id,
type:event.event_type,
minute:event.event_minute,
team:event.event_team,
player_name:event.event_player,
player_id:event.event_player_id,
result:event.event_result
});
});
I understand that the second _.each loop should be iterating for every match, since very match has it's own events subarray. I'm just not sure how to structure this and have been struggling with it for a while.
I tried nesting that loop inside the _.each(matches, function(match) { loop but that didn't work.
Thank you.
Edit: How could I get this to work?
var results = new Results({
start_date: lastWeek_string,
end_date: today_string,
matches:[
match_events: []
]
});
Because then as #zangw says I could construct the match_events array first, append it to matches, and so on.

Related

How to get data from database in array format using node js and MySql

I am using node.js as server language and Mysql as database so I am running query and getting data from database but is is showing in format like this
[ BinaryRow { name: 'Dheeraj', amount: '77.0000' },
BinaryRow { name: 'Raju', amount: '255.0000' } ]
What I want is
['Dheeraj', 77.0000],
['Raju', 66255.000030],
This what I am doing in my backend (node.js):
My model:
static getChartData(phoneNo, userType) {
let sql = 'select businessname as name,sum(billamt) amount from cashbackdispdets where consphoneno =' + phoneNo + ' group by businessid order by tstime desc limit 10'
return db.execute(sql, [phoneNo]);
My controller:
exports.getColumnChart = function(req, res) {
const phoneNo = req.body.userId
const userType = req.body.userType
console.log(phoneNo)
dashboardModule.getChartData(phoneNo, userType)
.then(([rows]) => {
if (rows.length > 0) {
console.log(rows)
return res.json(rows)
} else {
console.log("error")
return res.status(404).json({ error: 'Phone No. already taken' })
}
})
.catch((error) => {
console.log(error)
return res.status(404).json({ error: 'Something went wrong !!' })
})
}
I am sending this data to Ui and when I am receiving it on UI it is in the form of object inside array which is not the required data type I want
axios().post('/api/v1/Dashboard/DashboardColumnChart',this.form)
.then(res=>{
console.log(res.data)
debugger
this.chartData= res.data
})
The above code consoles on browser like
I am not getting any idea how o do it should I do it with backend or with front end and how
Nodejs will send you a JSON response if you want to change it. It is better to change or maniuplate it in a Front end framework. But if you want to change it in backend as you have asked Make sure that the rows is in the format that you want to recive.
let data = [
{ "name": "Dheeraj", "amount": "77.0000" },
{ "name": "Raju", "amount": "255.0000" }
]
// empty array to store the data
let testData = [];
data.forEach(element => {
testData.push(element.name)
});
You can format it using array.map and Object.values. map functions loops over each element and returns a modified element according to the callback provided. Object.values simply returns all the values of an object in an array.
const data = [ { "name": "Dheeraj", "amount": "77.0000" }, { "name": "Raju", "amount": "255.0000" } ];
const formattedData = data.map(obj => Object.values(obj));
console.log("Initial Data: ", data);
console.log("Formatted Data: ", formattedData);
// Map function example
const a = [1,2,3]
const mappedA = a.map(e => e * 2)
console.log(a, " mapped to: ", mappedA);
// Object.values example
const b = { firstName: 'John', lastName: 'Doe', number: '120120' }
console.log(Object.values(b));

DocumentDB: bulkImport Stored Proc - Getting 400 Error on Array/JSON issue

I'm simply trying to execute the standard example bulkImport sproc for documentDB API and I can't seem to pass it an array of objects. I always get 400 errors despite the documentation giving clear direction to send an array of objects
.. very frustrating.
Additional details: Even if I wrap the array in an object with the array under a property of 'items' and include it in my sproc it still errors out saying the same bad request, needs to be an object or JSON-serialized. When I try to do JSON.stringify(docs) before sending it fails to parse on the other side.
Bad Request: The document body must be an object or a string representing a JSON-serialized object.
bulkInsert.js:
https://github.com/Azure/azure-documentdb-js-server/blob/master/samples/stored-procedures/BulkImport.js
My Code (using documentdb-util for async):
execProc(docs, insertProc);
async function execProc(docs, insertProc){
let database = await dbUtil.database('test');
let collection = await dbUtil.collection(database, 'test');
let procInstance = await dbUtil.storedProcedure(collection, insertProc);
try{
let result = await dbUtil.executeStoredProcedure(procInstance, docs);
console.log(result);
} catch(e){
console.log(e.body)
}
}
Header
Object {Cache-Control: "no-cache", x-ms-version: "2017-11-15",
User-Agent: "win32/10.0.16299 Nodejs/v8.9.0 documentdb-nodejs-s…",
x-ms-date: "Mon, 11 Dec 2017 07:32:29 GMT",
Accept:"application/json"
authorization: myauth
Cache-Control:"no-cache"
Content-Type:"application/json"
User-Agent:"win32/10.0.16299 Nodejs/v8.9.0 documentdb-nodejs-sdk/1.14.1"
x-ms-date:"Mon, 11 Dec 2017 07:32:29 GMT"
x-ms-version:"2017-11-15"
Path
"/dbs/myDB/colls/myColl/sprocs/myBulkInsert"
Params
Array(3) [Object, Object, Object]
length:3
0:Object {id: "0001", type: "donut", name: "Cake", …}
1:Object {id: "0002", type: "donut", name: "Raised", …}
2:Object {id: "0003", type: "donut", name: "Old Fashioned", …}
[{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.35
},
{
"id": "0003",
"type": "donut",
"name": "Old Fashioned",
"ppu": 0.25
}]
The "docs" must be an array of array of params, otherwise, the procedure executor will treat them as multiple params of the procedure, not a single-array-param.
the following code works when call storedProcedure to pass argument with array type.
JS:
var docs = [{'id':1},{'id':2}];
executeStoredProcedure(proc, [docs])
C#
var docs = new[] {new MyDoc{id=1, source="abc"}, new MyDoc{id=2, source="abc"}];
dynamic[] args = new dynamic[] {docs};
ExecuteStoredProcedureAsync<int>(
procLink,
new RequestOptions {PartitionKey = new PartitionKey("abc")},
args);
NOTE: you must ensure the 'docs' have the same partition key, and pass partion key in RequestionOptions
I had the same problem. I was able to get it to work by Stringify the Array and parse it in the stored procedure. I opened an issue on the github where that code originated as well. Below is what worked for me. Good luck.
---- Stringify Array
var testArr = []
for (var i = 0; i < 50; i++) {
testArr.push({
"id": "test" + i
})
}
var testArrStr = JSON.stringify(testArr)
//pass testArrStr to stored procedure and parse in stored procedure
---- Slightly altered original BulkImport
exports.storedProcedure = {
id: "bulkImportArray",
serverScript:function bulkImportArray(docs) {
var context = getContext();
var collection = context.getCollection();
var docsToCreate = JSON.parse(docs)
var count = 0;
var docsLength = docsToCreate.length;
if (docsLength == 0) {
getContext().getResponse().setBody(0);
}
var totals = ""
function insertDoc(){
var msg = " count=" + count+" docsLength=" +docsLength + " typeof docsToCreate[]=" + typeof docsToCreate+ " length =" + docsToCreate.length
if(typeof docsToCreate[count] != 'undefined' ) {
collection.createDocument(collection.getSelfLink(),
docsToCreate[count],
function (err, documentCreated) {
if (err){
// throw new Error('Error' + err.message);
getContext().getResponse().setBody(count + " : " + err);
}else{
if (count < docsLength -1) {
count++;
insertDoc();
getContext().getResponse().setBody(msg);
} else {
getContext().getResponse().setBody(msg);
}
}
});
}else{
getContext().getResponse().setBody(msg);
}
}
insertDoc()
}
}
If you want to test it in the portal Script Explorer I had to create an escaped string i.e.
var testArr = []
for(var i=200; i<250; i++){
testArr.push({"id":"test"+i})
}
var testArrStr = JSON.stringify(testArr)
console.log('"'+testArrStr.replace(/\"/g,'\\"') + '"')

Modify nested object with multiple keys without replacing existing keys using Mongoose/NodeJS

Schema and model:
var schema = new mongoose.Schema({
timestamp_hour: Date,
deviceID: Number,
minutes: {
'0': {temperature: Number},
'1': {temperature: Number},
.
.
.
'59': {temperature: Number}
}
},{
collection: 'devices'
});
var model = mongoose.model('deviceData', schema);
Now in a POST request, I receive some data from an external source containing a timestamp, deviceID and temperature value.
My primary key is timestamp_hour and deviceID, so if there is an existing document in the database, I need to store the temperature value in minutes: {[minute_value]: temperature}. I currently derive minute_value from the timestamp, and I can query the database, all well and good. Now I need to update the minutes object in the document by adding the new key-value pair.
So after deriving the required values, I try running this:
var query = {timestamp_hour: timestamp, deviceID: deviceID};
var update = {minutes: {[minute]: {temperature: tempData}}};
deviceData.findOneAndUpdate(query, update, {upsert: true}, function(err, doc){
if(err) return res.send(500, {error: err});
return res.send("successfully saved");
});
Now the issue is, it replaces the entire minutes object inside document with the new single value.
Example:
Original document:
{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "38" : { "temperature" : 39.5 } },
}
Document after update:
{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "39" : { "temperature" : 38.0 } },
}
What I need:
{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "38" : { "temperature" : 39.5 }
"39" " { "temperature" : 38.0 } },
}
I'm new to MEAN, but I can see why my approach doesn't work since the update call just modifies the nested object.
I'd appreciate any help regarding the correct approach to use for achieving this functionality.
You can do this within a single update using a combination of the dot and bracket notations to construct the update object as follows:
var query = { "timestamp_hour": timestamp, "deviceID": deviceID },
update = { "$set": { } },
options = { "upsert": true };
update["$set"]["minutes."+ minute] = { "temperature": tempData };
deviceData.findOneAndUpdate(query, update, options, function(err, doc){
if(err) return res.send(500, {error: err});
return res.send("successfully saved");
});
Okay, so this works:
deviceData.findOne(query, function(err, doc) {
if(err) return done(err);
if(!doc){
data.save(function(err){
if(err) throw err;
res.json({"Result":"Success"});
});
} else {
doc.minutes[minute] = {temperature: tempData}
doc.save(function(err) {});
res.json(doc);
}
});

Cannot see a field added on a JSON document with Nodejs and Mongoose

if I query MongoDB with a simple query like this using mongoose:
User
.find()
.where('address.loc').near({ center: [lat,lng], maxDistance: 1 })
.exec(function(err, result) {
if (err) {
request.log(['server', 'database', 'error'], 'An error occured during the execution of the query');
}else{
for(var i=0;i<result.length;++i){
result[i]["distance"] = 5;
}
console.log(result[0].distance);
console.log(result[0])
}
});
The first console.log prints : 5
But the second one prints :
{ address: { loc: [ 37.0814402, 15.287517 ], value: 'viale tica' },
tags: [ 'Primi', 'Secondi' ],
__v: 0,
cap: 96100,
ad_number: 15,
business_email: 'prova#provbhifbvvyvg',
_id: 571b3b78249a2e160b4eee3f }
Why this document and the others in the result array are without the field distance?
Because result[0] is a mongoose document object. And when you call console.log(result[0]) the result is converted to the string (with mongoose document toString function). But mongoose document doesn't contain distance field.
To do what you want, you should convert each document to object:
var objects = results.forEach(results, function(res) {
res = res.toObject();
res["distance"] = 5;
return res;
});
console.log(objects[0].distance);
console.log(objects[0]);
http://mongoosejs.com/docs/api.html#document_Document-toObject

Loop to add data to complex JSON object

I have a complex JSON Object like this:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {
CustomerID: 400, CustomerName: "John"
} }
] } ] };
I am trying to do two things:
Declare this object but with the variable data empty
With a loop, add items dynamically to the data object,
How can I do it?
This isn't too complex an object. And it isn't JSON until it's converted into a string.
Right now, it's just plain-ol' JS objects and arrays.
Breaking that down into its elements might look like this:
var requestData = {};
requestData.__batchRequests = [];
requestData.__batchRequests[0] = {};
requestData.__batchRequests[0].__changeRequests = [];
requestData.__batchRequests[0].__changeRequests[0] = {};
requestData.__batchRequests[0].__changeRequests[0].requestUri = "Customers";
requestData.__batchRequests[0].__changeRequests[0].method = "POST";
requestData.__batchRequests[0].__changeRequests[0].headers = { "Content-ID" : "1" };
requestData.__batchRequests[0].__changeRequests[0].data = {};
Aside from the repeats, what do you see?
Personally, I see that __changeRequests[0] is an object as simple as:
var changeRequest = {
requestUri : "Customers",
method : "POST",
headers : { "Content-ID" : "1" },
data : {}
};
I also see that I can just push that onto my array of change requests:
requestData.__batchRequests[0].__changeRequests.push(changeRequest);
Right?
I also know that my changeRequest variable still points to the one that I just added to the array, and whatever I change on the object will show up as changed in the array's reference to the object, too:
changeRequest.data.CustomerName = "Bob";
changeRequest.data.CustomerID = "204";
requestData.__/*...*/changeRequests[0].data.CustomerName; // Bob
So how about writing yourself some helper-functions?
function extend (obj, additions) {
var key;
for (key in obj) { if (additions.hasOwnProperty(key)) {
obj[key] = additions[key];
}
}
function makeChangeRequest (url, method, headers, data) {
var request = {
requestUri : url,
method : method,
headers : {},
data : {}
};
extend(request.headers, headers);
extend(request.data, data);
return request;
}
function getBatch (num) { return requestData.__batchRequests[num]; }
var changeReq = makeChangeRequest("Customers",
"POST",
{ "Content-ID" : "1" },
{ CustomerName : "Bob", CustomerID : "2012" });
var batch = getBatch(0);
batch.__changeRequests.push(changeReq);
If you want to add more data to changeReq.data later:
extend(changeReq.data, { Address : "33 Nowhere Rd.", City : "Splitsville" });
For the first part of your question, you can initialize data with an empty associative array:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {} }
] } ] };
This next part assumes, perhaps incorrectly, that you can use jQuery. It also assumes that you have an array containing all of the relevant key value pairs.
var customerDeetsArray =[{CustomerID: 400}, {CustomerName: "John"}];
for (var i in customerDeetsArray) {
requestData.data = $.extend(requestData.data, customerDeetsArray[i]);
}
See working example which makes use of console.debug:
http://jsfiddle.net/4Rh72/6/