With a source JSON file below, I wish to read in , and apply the delta from a ```changes.JSON file. There is a more elegant way using direction mutation than reading into an array and writing back out. Curious how to do the direct mutation on the object and merge the changes into the source? The changes.json file has "action" and "payload" keys to direction operations on changes.json
source.json
{
"users" : [
{
"id" : "1",
"name" : "Dave Mustaine"
}
]
}
changes.json
{
"users": [{
"action": "add",
"payload": [{
"id": "2",
"name": "James Hetfield"
}
]
}]
becomes this:
{
"users" : [
{
"id" : "1",
"name" : "Dave Mustaine"
},
{
"id" : "2",
"name": "James Hetfield"
]
}
In my noob implementation I have all the logic written to parse out the action and payload, but currently writing into an array, but I think that is unnecessary and there is a more elegant way to just directly mutate the object and then stringify it and write out the updated json.
Here is what I have so far:
// Stream in source file
fs.readFile('./' + inputFile, (err, data) => {
if (err) throw err;
let input = JSON.parse(data);
//console.log(input);
});
// Stream in changes file
fs.readFile('./' + changesFile, 'utf-8', (err, jsonString) => {
if (err) {
console.log(err);
} else {
try {
const data = JSON.parse(jsonString);
const array = [];
Object.entries(data).map(([key, [{ action, payload }]]) => {
switch (key) {
case 'users': {
if (action === 'add') {
console.log("it's an add");
array.push([`${key}`, `${payload}`]);
}
break;
}
case 'playlists': {
if (action === 'add') {
console.log("it's an add");
array.push([`${key}`, `${payload}`]);
}
break;
}
case 'songs': {
if (action === 'add') {
console.log("it's an add");
array.push([`${key}`, `${payload}`]);
}
break;
}
}
});
console.log(array);
} catch (err) {
console.log('Error parsing JSON', err);
}
}
});
// after we have merged changes and source we need to write out
fs.appendFile('./' + outputFile, JSON.stringify(array, null, 2), err => {
if (err) {
console.log(err);
} else {
console.log('File sucessfully written');
}
});
Related
I have one question about a problem that I'm not able to fix. I try to update push a string passed via Query in my mongoose collection.
My collection are like this:
{
"_id": {
"$oid": "6199288597e42bf84d017f9e"
},
"name": "Lisa",
"surname": "Bianchi",
"ID_school": "afbH598U3",
"classes": [
{
"class": "5A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017f9f"
}
},
{
"class": "1A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017fa0"
}
}
],
"email": "insegnante#a.com",
"__v": 0
}
and I try to push a string in in_progress array that match, for example, with class:"5A" using this way:
import db from "../models/index.js";
const Teacher = db.teacher
const updateActivity = (req, res) => {
const query = { _id: req.query.id};
const update = {$push:{'classes.$[group].activities.in_progress': req.query.data } };
const options = {arrayFilters: { 'group.class': req.query.class }};
Teacher.findOneAndUpdate(query, update, options).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
const API = {
updateActivity
}
export default API
The query works fine, but nothing was pushed. I tested whit Insomnia passing in the Query field
id = 6199288597e42bf84d017f9e;
class:'5A';
data:"pushed"
Any suggestion? Thanks!
try this way by passing classes.class in query and also change push to $push:{'classes.$.activities.in_progress': req.query.data }
const updateActivity = (req, res) => {
const query = { _id: req.query.id ,'classes.class': req.query.class};
const update = {$push:{'classes.$.activities.in_progress': req.query.data } };
Teacher.updateOne(query,update).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
There are two ways of doing this:
Option 1: arrayFilters - more flexible Docu
The option you are using.
You have a syntax error - arrayFilters should be an array of documents.
const updateActivity = (req, res) => {
const query = { _id: req.query.id };
const update = {
$push:{ 'classes.$[group].activities.in_progress': req.query.data }
};
// This MUST be an array of filter documents!
const options = { arrayFilters: [{ 'group.class': req.query.class }] };
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}
Option 2: Via Query (as answered by #Saurabh Mistry)
Repeating his answer for completeness
By specifying a query that targets a particular element in an array within result documents.
const updateActivity = (req, res) => {
const query = {
_id: req.query.id,
'classes.class': req.query.data,
};
const update = {
$push:{ 'classes.$.activities.in_progress': req.query.data }
};
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}
the following array list I need to get all the price one by one.
this returns the full json object console.log('File data:', jsonString); but the for loop never seems to get called , it never enters it. I need to loop through a json file but its in different folder the json file is under menu folder called list.json menu-> projectName\menu\list.json the file looks like this
The data:
[
{
"code": "ZC",
"price": "1"
},
{
"code": "ZS",
"price": "3"
},
{
"code": "VC",
"price": "4"
},
...]
JS:
const jsonList = fs.readFile("../menu/list.json", "utf8", (err, jsonString) => {
if (err) {
console.log("File read failed:", err);
return;
}
console.log("File data:", jsonString);
console.log("File data:", jsonString.url);
for (var key in jsonString) {
if (jsonString.hasOwnProperty(key)) {
console.log("===>", jsonString[key].price);
}
return jsonString;
}
});
There are two ways to fix the issue you are facing, one is to have your code run inside the callback:
const jsonList = fs.readFile("../menu/list.json", "utf8", (err, jsonString) => {
if (err) {
console.log("File read failed:", err);
return;
}
console.log("File data:", jsonString);
for (var key in JSON.parse(jsonString)) {
if (jsonList.hasOwnProperty(key)) {
console.log("===>", jsonList[key].price); // This is never called
}
}
});
or by using sync function to read file:
const jsonString = fs.readFileSync("../menu/list.json", "utf8");
console.log("File data:", jsonString);
const jsonList = JSON.parse(jsonString);
for (var key in jsonList) {
if (jsonList.hasOwnProperty(key)) {
console.log("===>", jsonList[key].price); // This is never called
}
}
I think you need to loop in the callback as it is async and so jsonList is not the object you expect when you access it. See Get data from fs.readFile
I have an api which return data structured like this :
//code
return response.status(200).json(startdate)
results data:
[
"2020-01-16",
"2020-01-18",
]
i want that this api to return result like this:
Code: 200
Content:
{
"availableDates": [
"2017-11-24",
"2017-11-27"
],
"status": "SUCCESS",
"message": ""
}
this is my full code where i get the data as array
app.get('/api/getBusyDays',(request, response) =>{
odoo.connect(function (err) {
console.log(' OdooStartDate' + dateTimeStartUsed + 'OdooStopdate' + dateTimeEndUsed);
var params1 = [];
params1.push(inParams1);
console.log(' search params '+ JSON.stringify(params1));
odoo.execute_kw('calendar.event', 'search_read', params1, function (err, value) {
if (err) { return console.log(err) }
if(value) {
if (value.length > 0) {
value.forEach(function(a) {
a.start_datetime = moment(a.start_datetime).format('YYYY-MM-DD');
a.stop_datetime = moment(a.stop_datetime).format('YYYY-MM-DD');
});
const startdate = [...new Set(value.map(val => val.start_datetime))];
startdate.sort();
// return response.status(200).json( value)
return response.status(200).json(startdate)
}
}
you can just create an object like this:
let arrVal = [
"2017-11-24",
"2017-11-27"
];
// return Object or your framework (Express or KOA or) response Object
console.log({
"Code": 200,
"Content": {
"availableDates": arrVal,
"status": "SUCCESS",
"message": ""
}
})
Update:
Based on the comments on this answer, modify your response so it looks like this:
app.get('/api/getBusyDays',(request, response) =>{
odoo.connect(function (err) {
console.log(' OdooStartDate' + dateTimeStartUsed + 'OdooStopdate' + dateTimeEndUsed);
var params1 = [];
params1.push(inParams1);
console.log(' search params '+ JSON.stringify(params1));
odoo.execute_kw('calendar.event', 'search_read', params1, function (err, value) {
if (err) { return console.log(err) }
if(value) {
if (value.length > 0) {
value.forEach(function(a) {
a.start_datetime = moment(a.start_datetime).format('YYYY-MM-DD');
a.stop_datetime = moment(a.stop_datetime).format('YYYY-MM-DD');
});
const startdate = [...new Set(value.map(val => val.start_datetime))];
startdate.sort();
// return response.status(200).json( value)
return response.status(200).json({"code": 200, "content": {"availableDates": startdate, "status": "SUCCESS", "message": ""}})
}
}
You can create an empty object and set properties to it and send it as response from ur node api service.
let data = [
"2017-11-24",
"2017-11-27"
];
let response = [];
response.data = data;
response.code = 200;
response.status = 'success';
response.message = 'Mission Successful';
return response;
The property has been binded to the object questionaries list but it is not getting at the response time -
{
let cnt = 0;
questionnaire.find({"language" : defulatLang}, function (err, questionnaireList) {
if (questionnaireList !== null) {
async.eachSeries(questionnaireList,function(myquestions,callback){
questionnaire.find({'questionGroupId':"5a5ed4917c33629c1d383b8d"}, function (err, groups) {
questionnaireList[cnt].languagelist=groups;
// console.log("binded",questionnaireList[cnt].languagelist);
if(questionnaireList.length == cnt+1){
console.log("hello from response",questionnaireList)
res.json({
"code": 200,
"status": "success",
"message": "Questionnaire list",
"data": questionnaireList
});
}
cnt ++;
});
callback();
});
}
i want response in such a way that the binded property shoould also be send with response
You can do it like this -
let cnt = 0;
questionnaire.find({ "language": defulatLang }, function (err, questionnaireList) {
if (questionnaireList !== null) {
async.eachSeries(questionnaireList, function (myquestions, callback) {
questionnaire.find({ 'questionGroupId': "5a5ed4917c33629c1d383b8d" }, function (err, groups) {
if (err) {
return callback(err);
}
questionnaireList[cnt].languagelist = groups;
// console.log("binded",questionnaireList[cnt].languagelist);
if (questionnaireList.length == cnt + 1) {
console.log("hello from response", questionnaireList)
res.json({
"code": 200,
"status": "success",
"message": "Questionnaire list",
"data": questionnaireList
});
}
cnt++;
callback(null);
});
})
}
console.log("questionnaireList is null ", questionnaireList);
console.log("err ", err);
});
You have not handle the eachSeries callback properly.
Just Try this.
I have problem to insert a value inside an array using node.js and mongodb
1). MongoDb Schema
var userScore = new Schema({
child: {
quiz_level: {
current_level: {type:Number},
level_attempted: {
type: Array,
level_id: {type:Number},
level_complete: {type:Boolean},
level_score: {type:Number}
}
}
}
});
2). Node js
try{
// var quiz = levelScoreQuiz.child;
var userObj = {
"child.quiz_level.level_attempted.level_score": req.body.score
};
var user = new levelScoreQuiz(userObj);
user.save(function(err, result){
if (err) {
console.log('Error While Saving the reuslt ' +err)
} else {
console.log("User score saved successfully");
res.json(result);
}
});
} catch(err){
console.log('Error While Saving the reuslt ' +err);
return next(err);
}
3). Json result
This will shows the empty result of array insertions
{
"__v": 0,
"_id": "57832f610118546713d23466",
"child": {
"quiz_level": {
"level_attempted": [] //This is the empty array
}
}
}