i have a question, how can i set a json code in Braces/{} ?
all code in down explained what i need do
i want to do this for login system if i have any error i'm sorry for that
look like that
{
"test": "test",
"test1": "test1"
}
that my code
var usac = JSON.stringify({username: newusername, password: newpassword }, null, 2)
fs.appendFile('account.json', usac, fin)
function fin(err){
console.log("done")
}
that my json code
{
"username": "test",
"password": "test"
}{
"username": "test1",
"password": "test1"
}{
"username": "test2",
"password": "test2"
}{
"username": "test3",
"password": "test3"
}{
"username": "test4",
"password": "test"
}
i want code be right that
{
"user" :{
"username": "test",
"password": "test"
}
"user1" :{
"username": "test1",
"password": "test1"
}
"user2" :{
"username": "test2",
"password": "test2"
}
"user3" :{
"username": "test3",
"password": "test3"
}
"user4" :{
"username": "test4",
"password": "test4"
}
}
You are appending to a json file. But, the content is not json.
One quick solution is:
Create the file with {} as initial content.
Read the file
Parse the contents to JavaScript Object
Set new account object in the parsed object with username as key & account object as value.
Stringify the JavaScript Object
Overwrite the same file with the stringified data
const fs = require('fs');
class AccountsInterface {
constructor(filePath) {
this.filePath = filePath;
}
getAll(callback) {
fs.readFile(this.filePath, function onReadComplete(error, content) {
if(error) {
return callback(error);
}
const accountsMap = JSON.parse(content.toString());
callback(null, accountsMap);
});
}
addAccount(account, callback) {
const self = this;
self.getAll(function onAccountsLoaded(error, accountsMap) {
if(error) { return callback(error); }
accountsMap[account.username] = account;
const accountsMapString = JSON.stringify(accountsMap);
fs.writeFile(self.filePath, accountsMapString, function onWriteComplete(error) {
if(error) { return callback(error); }
callback();
});
});
}
// Async version
async getAllAsync() {
const content = await fs.promises.readFile(this.filePath);
const accountsMap = JSON.parse(content.toString());
return accountsMap;
}
async addAccountAsync(account) {
const accountsMap = await this.getAllAsync();
accountsMap[account.username] = account;
const accountsMapString = JSON.stringify(accountsMap);
await fs.promises.writeFile(this.filePath, accountsMapString);
}
}
// Ensure this file's contents are `{}` in the beginning
const accountsFilePath = './accounts.json';
const accountsInterface = new AccountsInterface(accountsFilePath);
const account = { username: 'test', password: 'test'};
accountsInterface.addAccount(account, onAccountAdded);
function onAccountAdded(error) {
if(error) { return console.log(error); }
// here, the accounts file will look like {"test": {"username": "test", "password": "test"}}
}
// Async version
const account = { username: 'test2', password: 'test2'};
await accountsInterface.addAccountAsync(account);
// here, the accounts file will look like {"test": {"username": "test", "password": "test"}, "test2": {"username": "test2", "password": "test2"}}
Related
I am not great with MongoDB's advanced techniques.
My record in the MongoDB collection:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Member",
},
{
"_user": ObjectId("3"),
"role": "Member",
}
],
}
Node.js / ExpressJS
I created API to update the array like below but did not work.
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
try {
const project = await Project.updateMany(
{ _id: req.params.projectID },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
I use the API parameter to get the project ID. Here is the request body data:
{
userID : ["2","3"];
role: "Admin"
}
So the API will get an array of userID to match and set all "role" fields to "Admin" to all matched.
I wanted the data to be like this:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Admin",
},
{
"_user": ObjectId("3"),
"role": "Admin",
}
],
}
Am I doing the right practice? If it is bad practice, what is the best way to solve this?
The query is fine. Just make sure that you pass the value with the exact type as in the MongoDB document.
var mongoose = require('mongoose');
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
userID = userID.map(x => mongoose.Types.ObjectId(x));
try {
const project = await Project.updateMany(
{ _id: mongoose.Types.ObjectId(req.params.projectID) },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
}
I'm having hard time on thinking how will I populate hooks with API response(json)
see below codes
cosnt [loginResponse, setloginResponse] = useState({
Token: '',
UserID: '', //from user-id
UserName: '', //from user-userName
firstName: '', //from user-firstName
rcCode: '' //from attributes-rcCode
})
const login = async () => {
await axios.get('/API')
.then(response => {
console.log('response.data', response.data.resp)
});
}
here's the result of console.log(response.data.resp)
{
"data": {
"token": "abcd",
"user": {
"id": "123456",
"userName": "uname",
"firstName": "FNAME",
"lastName": "MNAME",
"email": "email#email.com",
"attributes": {
"favorites": ["FAV"],
"rcCode": ["123"]
},
"requiredActions": [],
"roles": ["ROLE"]
},
"modulePermissions": []
}
}
for console.log(response.data):
"resp": {
"data": {
"token": "abcd",
"user": {
"id": "123456",
"userName": "uname",
"firstName": "FNAME",
"lastName": "MNAME",
"email": "email#email.com",
"attributes": {
"favorites": ["FAV"],
"rcCode": ["123"]
},
"requiredActions": [],
"roles": ["ROLE"]
},
"modulePermissions": []
}
},
"success": true
I want to populate my hooks with those datas for me to utilize it on my page.
I got undefined if I tried to console.log(response.data.resp.data)
On console.log(response), I got:
Thank you.
Don't use async/await and .then() together. Use either of those.
const login = async () => {
const response = await axios.get('/API');
const parsedData = JSON.parse(response.data.resp);
const userData = parsedData.data;
setLoginResponse({
Token: userData.token,
UserID: userData.user.id,
UserName: userData.user.userName,
firstName: userData.user.firstName,
rcCode: userData.user.attributes.rcCode
});
}
In the .then
setLoginResponse({...loginResponse, Token: response.data.resp.data.token, UserId: response.data.resp.data.user.id, ...}
You can destructure your response object first and store values in variables to make the setLoginResponse more easy to read.
https://reactjs.org/docs/hooks-state.html
If i have an array like:
[
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
But it's not always being returned in that order - how can i check if ryan, for example, exists somewhere in one of these objects?
If you are already using lodash (or want to) then I would use its find:
_.find(array, { user: "ryan" })
Or with a few more characters you can do it without lodash:
array.find(elem => elem.user === "ryan")
Both return undefined if a matching element is not found.
Function return true if array contains ryan.
var input = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
var output = input.some(function(eachRow){
return eachRow.user === 'ryan';
});
console.log(output);
My method to solve that is to extract the targeted fields into arrays then check the value.
const chai = require('chai');
const expect = chai.expect;
describe('unit test', function() {
it('runs test', function() {
const users = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "ryan#co.com"
}
];
const names = extractField(users, 'user'); // ['tom', 'james', 'ryan']
expect(names).to.include('ryan');
});
function extractField(users, fieldName) {
return users.map(user => user[fieldName]);
}
});
I'm using chai for assertion. In case you want to check in other fields, we just use the extract methods.
const emails = extractField(users, 'email');
expect(emails).to.include('ryan');
Hope it helps
I'm new use nodejs and mongodb, now I build restful API use nodejs and mongodb. I want use response standard for my API with http://jsonapi.org standard.
I need a suggestion from advance how best way to do it, making my API response like the following JSON data:
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
"links": {
"self": "http://example.com/users"
},
"data": [{
"type": "users",
"id": 5b647bb8998248235a0aab3c,
"attributes": {
"username": "luke",
"email": "luke#mail.com",
"password": "password",
"hashpassword":"",
"oldpassword":"$2a$10$eyt6YV6m2JJrebNxvS0iEuxMCubDXratNJ6/XK797IGvepXBdp9Yq",
"salt":"2q6eN9U0vWFBsIF1MtB5WrgPiB8pldTS",
"usertype":"bisnis",
"userstatus":"not aktif"
}
}, {
"type": "users",
"id": 5b647bdf998248235a0aab3d,
"attributes": {
"username": "ken",
"email": "ken#mail.com",
"password": "password",
"hashpassword":"",
"oldpassword":"$2a$10$eyt6YV6m2JJrebNxvS0iEuxMCubDXratNJ6/XK797IGvepXBdp9Yq",
"salt":"2q6eN9U0vWFBsIF1MtB5WrgPiB8pldTS",
"usertype":"bisnis",
"userstatus":"not aktif"
}
}]
}
I have problem with nest iteration when create output as above. This my code:
const UsersModel = mongoose.model('Users');
//...show list user
exports.listUsers = (req, res) => {
UsersModel.find({}, (err, result) => {
if (err) {
res.send({code: 400, failed: 'Error 400'});
}
res.json(result);
});
};
And this is my result JSON:
[
{
"type": "users",
"userstatus": "not aktif",
"_id": "5b647bb8998248235a0aab3c",
"username": "luke",
"email": "luke#mail.com",
"password": "password",
"usertype": "bisnis",
"hashpassword": "$2a$10$eyt6YV6m2JJrebNxvS0iEuxMCubDXratNJ6/XK797IGvepXBdp9Yq",
"salt": "2q6eN9U0vWFBsIF1MtB5WrgPiB8pldTS",
"__v": 0
},
{
"type": "users",
"userstatus": "tidak aktif",
"_id": "5b647bdf998248235a0aab3d",
"username": "ken",
"email": "ken#mail.com",
"password": "password",
"usertype": "personal",
"hashpassword": "$2a$10$hok988mszyIBiXVNjmfifOiPNzXkBRRRynXJS/0qCkvlaBOQs65MO",
"salt": "IiMvtVYVqTpZFXmYQIM4IlS6PJFVZ3kw",
"__v": 0
}
]
And this is my temporary code for my problem.
//...show list user
exports.listUsers = (req, res) => {
UsersModel.find({}, (err, result) => {
if (err) {
res.send({code: 400, failed: 'Error 400'});
}
let listData = [];
for (let key in result) {
let data = {};
let attr = {};
if (result.hasOwnProperty(key)) {
data.type = result[key].type;
data.id = result[key]._id;
for(let i in result[key]) {
if(result[key].hasOwnProperty(i)) {
attr.username = result[key].username;
attr.email = result[key].email;
attr.password = result[key].password;
attr.hashpassword = result[key].hashpassword;
attr.oldpassword = result[key].oldpassword;
attr.salt = result[key].salt;
attr.usertype = result[key].usertype;
attr.userstatus = result[key].userstatus;
}
}
data.attribute = attr;
listData.push(data);
}
}
let collections = {
"meta": {
"copyright": "Copyright 2018 Kotakku Studio and Lab",
"authors": [
"sw. saputra"
]
},
"link": {
"self": req.protocol + '://' + req.get('host') + req.originalUrl
},
"data": listData
}
res.json(collections);
});
};
Please give me suggestion the elegant and the best way to solve my problem if my temporary code is not correct.
Thanks advance.
You need to create a proper mongoose schema according to your requirement and map the res to the schema.
//Schema for users
var UsersSchema = mongoose.Schema({
links: {
self: String
},
data:[{
type: String,
attributes: {
username: String,
.
.
.
}
}]
})
id for each document in an array will be created automatically by MongoDB.
For mongoose schema docs see http://mongoosejs.com/docs/guide.html
You can also check this simple TODO API for reference https://github.com/mkujaggi/node-course-todo-api
In this condition's statement:
if(result[key].hasOwnProperty(i)) {
You should be accessing the i of result[key]:
if(result[key].hasOwnProperty(i)) {
attr.username = result[key][i].username;
attr.email = result[key][i].email;
attr.password = result[key][i].password;
attr.hashpassword = result[key][i].hashpassword;
attr.oldpassword = result[key][i].oldpassword;
attr.salt = result[key][i].salt;
attr.usertype = result[key][i].usertype;
attr.userstatus = result[key][i].userstatus;
}
And you don't need all those .hasOwnProperty checks unless you're modifying native prototypes, which you probably shouldn't. And especially for the Array, it's not necessary if you'd just loop properly with a for instead of a for-in.
exports.listUsers = (req, res) => {
UsersModel.find({}, (err, result) => {
if (err) {
res.send({
code: 400,
failed: 'Error 400'
});
}
let listData = [];
let data = {};
let attr = {};
data.type = result[key].type;
data.id = result[key]._id;
for (let i = 0; i < result[key].length; i++) {
attr.username = result[key][i].username;
attr.email = result[key][i].email;
attr.password = result[key][i].password;
attr.hashpassword = result[key][i].hashpassword;
attr.oldpassword = result[key][i].oldpassword;
attr.salt = result[key][i].salt;
attr.usertype = result[key][i].usertype;
attr.userstatus = result[key][i].userstatus;
}
data.attribute = attr;
listData.push(data);
}
}
let collections = {
"meta": {
"copyright": "Copyright 2018 Kotakku Studio and Lab",
"authors": [
"sw. saputra"
]
},
"link": {
"self": req.protocol + '://' + req.get('host') + req.originalUrl
},
"data": listData
}
res.json(collections);
});
};
I would do something like this with iterating over the keys (this will work dynamically that is even if we don't know key names)
var test=[
{
"type": "users",
"userstatus": "not aktif",
"_id": "5b647bb8998248235a0aab3c",
"username": "luke",
"email": "luke#mail.com",
"password": "password",
"usertype": "bisnis",
"hashpassword": "$2a$10$eyt6YV6m2JJrebNxvS0iEuxMCubDXratNJ6/XK797IGvepXBdp9Yq",
"salt": "2q6eN9U0vWFBsIF1MtB5WrgPiB8pldTS",
"__v": 0
},
{
"type": "users",
"userstatus": "tidak aktif",
"_id": "5b647bdf998248235a0aab3d",
"username": "ken",
"email": "ken#mail.com",
"password": "password",
"usertype": "personal",
"hashpassword": "$2a$10$hok988mszyIBiXVNjmfifOiPNzXkBRRRynXJS/0qCkvlaBOQs65MO",
"salt": "IiMvtVYVqTpZFXmYQIM4IlS6PJFVZ3kw",
"__v": 0
}
]
var listData=[]
test.forEach((obj)=>{
var tempObj={attributes:{}}; //initialize tempObj
Object.keys(obj).forEach((key)=>{
if(key=="_id" || key=="type"){
tempObj[key]=obj[key];
}else{
tempObj.attributes[key]=obj[key];
}
})
listData.push(tempObj);
})
let collections = {
"meta": {
"copyright": "Copyright 2018 Kotakku Studio and Lab",
"authors": [
"sw. saputra"
]
},
"link": {
"self": 'test url'
},
"data": listData
}
console.log(collections)
I've created multiple REST API projects using the Laravel framework and basing my code structure on the Laracasts tutorial. However we are deciding to move some projects using NodeJs as a backend. I'm beginning to learn node and I'm trying to replicate it in Node. I was able to do it for a singe object response but for multiple objects I can't seem to make it work.
Here is my controller:
index(req,res) {
User
.findAll()
.then(function(users){
res.json(api.respond(transfomer.transformCollection(users)));
})
.catch(function(error){
res.json(api.respondWithError('users not found',error));
});
}
api controller:
module.exports = {
// response w/o error
respond: function(data,msg,status) {
if (msg == null) {
return {
'status': status || true,
'data': data
};
} else {
return {
'status': true,
'message': msg,
'data': data
};
}
},
// response with error
respondWithError: function(msg,error) {
var self = this;
var status = false;
var data = {
'error': error
};
return this.respond(data,msg,status);
},
};
transformer.js
module.exports = {
// single transformation
transform (user) {
return {
'id' : user.id,
'username': user.username,
'firstname': user.firstname,
'lastname': user.lastname,
'address': user.address,
'phone': user.phone,
'mobile': user.mobile,
'status': user.status
};
},
//
transformCollection(users) {
var self = this;
var data = [];
for (var i = 0; i <= users.length; i++) {
data.push(this.transform(users[i]));
}
return data;
}
};
sample output
{
"status": true,
"data": [
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
{
"id": 1,
"username": "b#email.com",
"firstname": "Jon",
"lastname": "Doe",
"address": "Homes",
"phone": "+966501212121",
"mobile": "+966501212121",
"status": "NOT VERIFIED"
},
]
}
Sorry for asking this as I'm a bit newb with node. Is it possible to achieve that output as I tried different ways but Im still getting errors. Btw I'm using sequelize for the database.
Thanks.
You can use this:
const options = {
raw: true,
attributes: ['id', 'name', 'code', 'createdAt','updatedAt']
};
country.findAndCountAll(options).then(querySnapshot => {
const total = querySnapshot.count;
resolve({
docs: querySnapshot.rows,
total: total
})
}).catch((err) => {
reject(err)
});
I've found the answer to my question since sequelize is returning the results as an object with additional properties aside from the database results I had to modify the controller to set and convert the results to raw in order for me to get the array of objects from the query results from the database.
index(req,res) {
User
.findAll({ raw: true }) // added "raw: true"
.then(function(users){
res.json(api.respond(transfomer.transformCollection(users)));
})
.catch(function(error){
res.json(api.respondWithError('users not found',error));
});
},
This will return the array of objects from the database and from there the data transformer is working properly. Thank you for all the help.