How to push messages objects to array in JSON object - javascript

I have a JSON object like this
{ "messages":["{date: 2017-8-23 12:50:05, name: aaa, msg: zzz}"]}
I want to push more objects to messages array after every message from user in Node.js but I only clone JSON object. How to fix this?
This is my code:
const JSONTemplate = (filePath, date, name, msg) => {
let obj = {
messages: [],
};
obj.messages.push(`{date: ${date}, name: ${name}, msg: ${msg}}`); //add some data
json = JSON.stringify(obj);
fs.appendFile(filePath, json, (err) => {
if (err) throw err;
}); }

You can try to put real object instead of string representation
obj.messages.push({date, name, msg});
But your question is still unclear for me. There is a mistake in string representation. You can not parse back your serialized object, because you miss apostrophe in your string.
And maybe you cannot get array of multiple values, because your rewrite your array by every function call.
const JSONTemplate = (filePath, date, name, msg, array = []) => {
let obj = {
messages: array,
};
obj.messages.push({date, name, msg}); //add some data
json = JSON.stringify(obj);
fs.appendFile(filePath, json, (err) => {
if (err) throw err;
}); }

if you want to append JSON data first you read the file and after that you could overwrite that.
const JSONTemplate = (filePath, date, name, msg) => {
fs.readFile(filePath, function (err, data) {
var json = JSON.parse(data);
//add some data
json.messages.push(JSON.stringify({date: ${date}, name: ${name}, msg: ${msg}}));
fs.writeFile(filePath, json, (err) => {
if (err) throw err;
});
});
}
also it's good practices to use try..catch to error handling when dealing with sync function like JSON.parse(), fs.readFileSync etc.
try{
var json = JSON.parse(data);
}catch(e){
throw e
}
Happy coding

Related

Write JavaScript object to an array inside a JSON file

How can I write a JavaScript object inside of an array that is inside a JSON file?
What I mean is: I'm making a Discord (message app) BOT, when the user uses the command "/add" the BOT will ask for 2 inputs, a "name" and an "artist" both this inputs make up a song so I'm creating an object called "data" for that song.
I also have a JSON file, that my database, what I want is, everytime this command is used, my object should the pushed inside of an array in my JSON file, so later on I can retrieve a random object inside of this array. How can I do that? I hope the question is not too confusing, thanks!
module.exports={
data: new SlashCommandBuilder()
.setName('add')
.setDescription('Add a song to the database.')
.addStringOption(option =>
option.setName('artist')
.setDescription('The artist of the song')
.setRequired(true))
.addStringOption(option =>
option.setName('name')
.setDescription('The name of the song')
.setRequired(true)),
async execute(interaction){
let name = interaction.options.getString('name');
let artist = interaction.options.getString('artist');
const data = { name: name, artist: artist};
await interaction.reply(`**` + artist + `**` + ` - ` + `**` + name + `**` + ` was added to the database.`)},
};
//WHAT YOU SEE FROM NOW ON IS A DIFFERENT FILE, A JSON FILE CALLED data.json with some examples of what it should look like
[
{
"name":"Die for You",
"artist":"The Weeknd"
},
{
"name":"FEAR",
"artist":"Kendrick Lamar"
}
]
You have to use node filesystem.
Import FS and use writeFile function.
https://nodejs.org/api/fs.html#filehandlewritefiledata-options
Dont forget about JSON.stringify to turn your object into string
const fs = require('fs');
const data = { name: name, artist: artist };
fs.writeFile("output.json", JSON.stringify(data), 'utf8', function (err) {
if (err) {
console.log("An error occured while writing JSON Object to File.");
return console.log(err);
}
console.log("JSON file has been saved.");
});
// Edit (Adding new objects to .json)
You have to read data from your file, add something and save again.
let rawdata = fs.readFileSync('data.json');
let data = JSON.parse(rawdata);
data.push({name: name, artist: artist});
// to use push() function data have to be an array, edit your .json file to " [] ",
// now you can add elements.
fs.writeFile("output.json", JSON.stringify(data), 'utf8', function (err) {
if (err) {
console.log("An error occured while writing JSON Object to File.");
return console.log(err);
}
console.log("JSON file has been saved.");
});
If you want to add something to an array, you .push it in there.
var arr = [];
arr.push(123);
arr.push({a:1,b:2});
arr.push(null);
arr.push("string");
console.dir(arr);

Express does not return valid response

i am trying to use mongodb to get some data for our analytics page, there's alot of data that's processing but for some reason the express returns empty array as response even when i use console log i see the data on terminal.
This is my endpoint
import Analytics from '../classes/Analytics';
import { Router } from 'express';
import role from '../middleware/role';
const router = Router();
router.use(role('admin'));
router.get('/analytics/weekly', async (req, res) => {
try {
const data = await Analytics.getWeekly();
return res.status(200).send({ data });
} catch (err) {
console.log(err);
return res.status(500).send({ message: 'Something went wrong, please try again later!' });
}
});
module.exports = router;
This is where all the magic happens for data variable
class Analytics {
static async getWeekly() {
// ignore this one day difference thing
const startDate = moment().subtract(1, 'days').startOf('week').format();
const endDate = moment().subtract(1, 'days').endOf('week').format();
try {
const orders = await Order.find(
{
sent_at: {
$gte: startDate,
$lte: endDate,
},
},
{ user: 1, created_at: 1, sent_at: 1 }
);
let counter = [];
for await (const item of orders) {
const date = moment(item.sent_at).format('YYYY-MM-DD HH');
if (!counter[date]) counter[date] = [];
if (!counter[date][item.user.username]) counter[date][item.user.username] = 0;
counter[date][item.user.username] += 1;
}
return counter;
} catch (err) {
console.log(err);
}
}
}
The point of the static method above is to fetch all orders and count how many times which user has handled the order.
Now when i console.log the data from the router endpoint i see the data on console perfectly just how i wanted it to be
'2021-07-03 22': [
Johnson: 10,
Mikaels: 15,
Vasquez: 24,
Blaskovich: 3
],
'2021-07-03 23': [
Johnson: 2,
Vasquez: 12,
Mikaels: 15,
Blaskovich: 5
]
The problem is when i make a request to my endpoint it returns an empty array []. What am i missing here?
Change this:
if (!counter[date]) counter[date] = [];
to this:
if (!counter[date]) counter[date] = {};
And this:
let counter = [];
to this:
let counter = {};
Your code here:
if (!counter[date][item.user.username]) counter[date][item.user.username] = 0;
Is adding a property to an array, not adding an array element. And JSON.stringify() ignores properties on an array. It only serializes actual array elements so when you try to send the JSON version of the array, it always appears empty.
So, when you call res.status(200).send({ data });, the .send() method serializes your object which contains a bunch of arrays that have no actual array elements, only properties.
By changing the arrays to be objects, then JSON.stringify() will serialize all those properties. Arrays and Objects have many things in common, but they are not the same. You should use the appropriate type for your situation.
In addition, change this:
} catch (err) {
console.log(err);
}
to this:
} catch (err) {
console.log(err);
throw err;
}
So that you are properly propagating errors back to the caller. Otherwise, you're just eating the error and returning undefined, both of which will cause problems for the caller.

FS write file is breaking my json, how to correctly update just one key?

I have a simple json object like so.
{
"gymData": {
"previousWorkouts": [
],
"exercises": [
]
}
}
both of the arrays above, are full of objects. I have 2 end points /workouts and /exercises.
my backend is just a simple express server with custom end points. when I add a new workout in the frontend and click submit, the /workouts endpoint behaves correctly.
however, I'm getting some issue when it's not updating the json correctly and resulting in a json error.
this is my node endpoint code
app.post("/exercises", function(req, res) {
fs.readFile('db.json', 'utf8', function (err, data) {
if (err) throw err;
let databaseData = JSON.parse(data);
const workoutExercises = req.body.workoutExercises.workouts
workoutExercises.forEach(exercise => {
const filteredExerciseDatabase = databaseData.gymData.exercises.filter(ex => ex.name === exercise.name)
filteredExerciseDatabase[0].previousWeights.push({date: req.body.date, weight: exercise.weight})
})
const updatedData = JSON.stringify(databaseData)
console.log(updatedData)
fs.writeFile('db.json', updatedData, 'utf8', function(err, data) {
if (err) throw err;
res.status(200).send("Basket was updated");
});
});
})
instead of writing the whole file again. I was wondering if I can just update the specific object key that I need too?
also, for reference, the error seems to be appending extra stuff onto the json object, so it's breaking. but in this line: console.log(updatedData) when I copy that logged data into a json validator, it is valid. so I'm confused as to why it's not writing the correct thing :/

mongoose forEach loop and update documents one by one

I want to query a collection and update each document using some value that i will get from another query which is gonna be built with some info from the returned document.
const mongoose = require('mongoose');
const userModel = {
country: { type: String }
newField: { type: String }
};
const myUsersModel = mongoose.model('user',userModel);
myUsersModel.find({country:"USA"}).forEach(function (doc) {
// another query here into a relation Database:
let anotherQuery = 'SELECT * FROM myTable WHERE name=' + doc.name;
mySQLConnection.query(
anotherQuery,
function selectCb(err, results, fields) {
if (err) {
console.log("ERROR: " + err.message);
throw err;
}
console.log("Got "+results.length+" Rows:");
let updatedInfo = results.SomeField;
// update the mongoose doc:
doc.newField = updatedInfo;
myUsersModel.save(doc);
});
mySQLConnection.end(function(err) {
console.log("connection ended.");
});
mongoose.connection.close();
});
I am getting the following error:
TypeError: myUsersModel.find(...).forEach is not a function
myUsersModel.find({country:"USA"})
.then(users=>users.forEach //users might be null here btw
Or if you want to keep your callback style
myUsersModel.find({country:"USA"}, function(err, users) {
if (err) throw err;
users.forEach
If a callback is not provided, Model.find returns an instance of Query and not an instance of Array.
Hence, you can not use forEach as Query is not an Array.

Get the _id of inserted document in Mongo database in NodeJS

I use NodeJS to insert documents in MongoDB. Using collection.insert I can insert a document into database like in this code:
// ...
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId; // = ???
});
// ...
How can I get the _id of inserted object?
Is there any way to get the _id without getting latest object inserted _id?
Supposing that in same time a lot of people access the database, I can't be sure that the latest id is the id of object inserted.
A shorter way than using second parameter for the callback of collection.insert would be using objectToInsert._id that returns the _id (inside of the callback function, supposing it was a successful operation).
The Mongo driver for NodeJS appends the _id field to the original object reference, so it's easy to get the inserted id using the original object:
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId = objectToInsert._id; // this will return the id of object inserted
});
There is a second parameter for the callback for collection.insert that will return the doc or docs inserted, which should have _ids.
Try:
collection.insert(objectToInsert, function(err,docsInserted){
console.log(docsInserted);
});
and check the console to see what I mean.
As ktretyak said, to get inserted document's ID best way is to use insertedId property on result object. In my case result._id didn't work so I had to use following:
db.collection("collection-name")
.insertOne(document)
.then(result => {
console.log(result.insertedId);
})
.catch(err => {
// handle error
});
It's the same thing if you use callbacks.
I actually did a console.log() for the second parameter in the callback function for insert. There is actually a lot of information returned apart from the inserted object itself. So the code below explains how you can access it's id.
collection.insert(objToInsert, function (err, result){
if(err)console.log(err);
else {
console.log(result["ops"][0]["_id"]);
// The above statement will output the id of the
// inserted object
}
});
if you want to take "_id" use simpley
result.insertedId.toString()
// toString will convert from hex
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
collection.save(function(err,room){
var newRoomId = room._id;
});
You could use async functions to get _id field automatically without manipulating data object:
async function save() {
const data = {
name: "John"
}
await db.collection('users').insertOne(data)
return data
}
Returns (data object):
{
    _id: '5dbff150b407cc129ab571ca',
    name: 'John',
}
Now you can use insertOne method and in promise's result.insertedId
#JSideris, sample code for getting insertedId.
db.collection(COLLECTION).insertOne(data, (err, result) => {
if (err)
return err;
else
return result.insertedId;
});
Similar to other responses, you can grab the variable using async await, es6+ features.
const insertData = async (data) => {
const { ops } = await db.collection('collection').insertOne(data)
console.log(ops[0]._id)
}
Another way to do it in async function :
const express = require('express')
const path = require('path')
const db = require(path.join(__dirname, '../database/config')).db;
const router = express.Router()
// Create.R.U.D
router.post('/new-order', async function (req, res, next) {
// security check
if (Object.keys(req.body).length === 0) {
res.status(404).send({
msg: "Error",
code: 404
});
return;
}
try {
// operations
let orderNumber = await db.collection('orders').countDocuments()
let number = orderNumber + 1
let order = {
number: number,
customer: req.body.customer,
products: req.body.products,
totalProducts: req.body.totalProducts,
totalCost: req.body.totalCost,
type: req.body.type,
time: req.body.time,
date: req.body.date,
timeStamp: Date.now(),
}
if (req.body.direction) {
order.direction = req.body.direction
}
if (req.body.specialRequests) {
order.specialRequests = req.body.specialRequests
}
// Here newOrder will store some informations in result of this process.
// You can find the inserted id and some informations there too.
let newOrder = await db.collection('orders').insertOne({...order})
if (newOrder) {
// MARK: Server response
res.status(201).send({
msg: `Order N°${number} created : id[${newOrder.insertedId}]`,
code: 201
});
} else {
// MARK: Server response
res.status(404).send({
msg: `Order N°${number} not created`,
code: 404
});
}
} catch (e) {
print(e)
return
}
})
// C.Read.U.D
// C.R.Update.D
// C.R.U.Delete
module.exports = router;

Categories