Json values from one file, based on fields from another Json file - node.js

I am trying to get values to a JSON file, based on field mapping from another JSON file.
I have a JSON file I get from external systems, which have different field names. I created a JSON file that will map the fields from the external system to the names I need the fields to be in:
{
"username":"user",
"externalSystemId":"id",
"active":"active",
"type":"type",
"patronGroup":"group",
"meta": {
"creation_date":"dateCreated",
"last_login_date":"lastLogin"
},
"personal": {
"lastName":"lname",
"firstName":"fname",
"email":"email",
"phone":"phone",
"mobilePhone":"mobile",
"dateOfBirth":"birthDate",
"addresses":{
"countryId": "countryCode",
"addressLine1": "address",
"addressLine2": "address2",
"city": "city",
"region": "region",
"postalCode": "zipcode",
"addressTypeId": "addressType",
"primaryAddress": "primary"
}
},
"enrollmentDate": "enrollmentDate",
"expirationDate": "expirationDate"
}
In this file, the fields are the fields I will need to populate, while the values are the names of the fields I get from the external system, which looks like this for example:
{
"user":"name",
"id":12345,
"active":true,
"type":"Student",
"group":"BA",
"dateCreated":"NOV 22 2019",
"lastLogin":"NOV 23 2020",
"lname":"Yard",
"fname":"Paul",
"email":"email#gmail.com",
"phone":"(000)-000-0000",
"mobile":"(000)-000-0000",
"birthDate":"OCT 11 1999",
"countryId": "US",
"addressLine1": "4th street",
"addressLine2": "25B",
"city": "NY",
"region": "NY",
"postalCode": "00000",
"addressTypeId": "Personal",
"primaryAddress": true,
"enrollmentDate": "MAR 22 2019",
"expirationDate": "MAR 21 2022"
}
So the end JSON file will need to look like this:
{
"username":"name",
"externalSystemId":12345,
"active":true,
"type":"Student",
"patronGroup":"BA",
"meta": {
"creation_date":"NOV 22 2019",
"last_login_date":"NOV 23 2020"
},
"personal": {
"lastName":"Yard",
"firstName":"Paul",
"email":"email#gmail.com",
"phone":"(000)-000-0000",
"mobilePhone":"(000)-000-0000",
"dateOfBirth":"OCT 11 1999",
"addresses":{
"countryId": "US",
"addressLine1": "4th street",
"addressLine2": "25B",
"city": "NY",
"region": "NY",
"postalCode": "00000",
"addressTypeId": "Personal",
"primaryAddress": true
}
},
"enrollmentDate": "MAR 22 2019",
"expirationDate": "MAR 21 2022"
}
I was thinking of using a dictionary/index to create this, but I've never done that before, nor am I sure how to do it.
Is there a simple way to do it?

This kind of mapping is easy with a dictionary when we have single level of JSON.
For a multi level JSON, we can make use of a recursive function to map the data from dictionary.
In the code lets say this is your JSON:
let json = {
username: "user",
externalSystemId: "id",
active: "active",
type: "type",
patronGroup: "group",
meta: {
creation_date: "dateCreated",
last_login_date: "lastLogin",
},
personal: {
lastName: "lname",
firstName: "fname",
email: "email",
phone: "phone",
mobilePhone: "mobile",
dateOfBirth: "birthDate",
addresses: {
countryId: "countryCode",
addressLine1: "address",
addressLine2: "address2",
city: "city",
region: "region",
postalCode: "zipcode",
addressTypeId: "addressType",
primaryAddress: "primary",
},
},
enrollmentDate: "enrollmentDate",
expirationDate: "expirationDate",
};
// Here is the dictionary:
// Note: the personal address field had incorrect mapping for few fields, I have modified the property to match the value of respective key of the JSON.
let dictionary = {
user: "name",
id: 12345,
active: true,
type: "Student",
group: "BA",
dateCreated: "NOV 22 2019",
lastLogin: "NOV 23 2020",
lname: "Yard",
fname: "Paul",
email: "email#gmail.com",
phone: "(000)-000-0000",
mobile: "(000)-000-0000",
birthDate: "OCT 11 1999",
countryCode: "US",
address: "4th street",
address2: "25B",
city: "NY",
region: "NY",
zipcode: "00000",
addressType: "Personal",
primary: true,
enrollmentDate: "MAR 22 2019",
expirationDate: "MAR 21 2022",
};
// recursive function to map the JSON, extract the actual value from from dictionary
function buildMapping(jsonParam) {
let result = {};
// iterate over the JSON parameter
for (const [key, value] of Object.entries(jsonParam)) {
if (typeof value === "object") {
// for type as object, make a recursive call with the object value as param
// collect the result of inner object
let resultInner = buildMapping(value);
// attach the result of the inner object to its key
result[key] = resultInner;
} else {
// check if the dictionary contains the mapping, otherwise set as null
result[key] = dictionary.hasOwnProperty(value)
? dictionary[value]
: null;
}
}
return result;
}
let resultJson = buildMapping(json);
console.log(resultJson);
Result:
{
username: "name",
externalSystemId: 12345,
active: true,
type: "Student",
patronGroup: "BA",
meta: { creation_date: "NOV 22 2019", last_login_date: "NOV 23 2020" },
personal: {
lastName: "Yard",
firstName: "Paul",
email: "email#gmail.com",
phone: "(000)-000-0000",
mobilePhone: "(000)-000-0000",
dateOfBirth: "OCT 11 1999",
addresses: {
countryId: "US",
addressLine1: "4th street",
addressLine2: "25B",
city: "NY",
region: "NY",
postalCode: "00000",
addressTypeId: "Personal",
primaryAddress: true,
},
},
enrollmentDate: "MAR 22 2019",
expirationDate: "MAR 21 2022",
};

Related

Add key in Joi object if key does not exist

I have a joi schema like this
Joi.object({
name: Joi.string(),
language: Joi.string(),
birthday: Joi.date(),
age: Joi.number().integer()
})
The input can contain birthday and age at the same time or just one of the keys. If one of the keys does not exist, I want the missing key to be automatically added with the string "NULL" like this
//input
{
"name": "Jane Doe",
"language": "de",
"birthday": "1960-06-27"
}
//modified to
{
"name": "Jane Doe",
"language": "de",
"birthday": "1960-06-27",
"age": "NULL"
}
Is there a way to automatically add a key with a default value, if the key is missing?
Use any.default([value]):
const schema = Joi.object({
name: Joi.string(),
language: Joi.string(),
birthday: Joi.date(),
age: Joi.number().integer().default(null)
});
console.log(schema.validate({
"name": "Jane Doe",
"language": "de",
"birthday": "1960-06-27"
}));
Output:
{
name: "Jane Doe",
language: "de",
birthday: Mon Jun 27 1960 01:00:00 GMT+0100 (Central European Standard Time),
age: null
}
I would prefer null rather then a string "NULL" because both date and age are not of type string.

How do i group my list off stories by user details

so here is my stories model,
const storySchema = new mongoose.Schema(
{
avatar: { type: String, default: null },
handle: { type: String, default: null },
new: { type: Boolean, default: true },
isLive: {type: Boolean, default: false},
url: { type: String },
type: { type: String },
userName: { type: String, default: null },
userId: { type: mongoose.Schema.Types.ObjectId, ref: "user_details" },
isDeleted: { type: Boolean, default: false}
},
{
timestamps: true,
minimize: false
}
)
userId is refered to user_details, so currently when i list stories they get listed like this ,
one story at a time and sorted by userId and createdAt,
As you can see the first 2 stories has the same userId, and what i want to do is that i group the stories by the user Object.
"status": true,
"data": [
{
"_id": "633564ab793cf2a65f7c5dad",
"avatar": null,
"handle": null,
"new": true,
"isLive": false,
"url": "https://ellingsen-group.s3.amazonaws.com/media-1664443562856.png",
"type": "",
"userName": null,
"userId": "62eb5d58512ef25f1352830b",
"isDeleted": false,
"createdAt": "2022-09-29T09:26:03.846Z",
"updatedAt": "2022-09-29T09:26:03.846Z",
"__v": 0
},
{
"_id": "633564a9793cf2a65f7c5daa",
"avatar": null,
"handle": null,
"new": true,
"isLive": false,
"url": "https://ellingsen-group.s3.amazonaws.com/media-1664443559395.png",
"type": "",
"userName": null,
"userId": "62eb5d58512ef25f1352830b",
"isDeleted": false,
"createdAt": "2022-09-29T09:26:01.032Z",
"updatedAt": "2022-09-29T09:26:01.032Z",
"__v": 0
},
{
"_id": "633564e6793cf2a65f7c5dba",
"avatar": null,
"handle": null,
"new": true,
"isLive": false,
"url": "https://ellingsen-group.s3.amazonaws.com/media-1664443621607.png",
"type": "",
"userName": null,
"userId": "6290a0e7f03b0b3585e0f740",
"isDeleted": false,
"createdAt": "2022-09-29T09:27:02.608Z",
"updatedAt": "2022-09-29T09:27:02.608Z",
"__v": 0
},
{
"_id": "633564bf793cf2a65f7c5db0",
"avatar": null,
"handle": null,
"new": true,
"isLive": false,
"url": "https://ellingsen-group.s3.amazonaws.com/media-1664443582519.png",
"type": "",
"userName": null,
"userId": "6290a0e7f03b0b3585e0f740",
"isDeleted": false,
"createdAt": "2022-09-29T09:26:23.519Z",
"updatedAt": "2022-09-29T09:26:23.519Z",
"__v": 0
}
],
"totalPages": 1,
"message": "Get user story Feed Success"
want to change this, so for user 1 ( story 1, 2, 3) user 2 ( story 1,2 ) etc,
here is the query for the result above.
const stories: any = await Story.StoryModel.aggregate([{ $match: { '_id': { $in: combined } } }, { $sort: { userId: -1, createdAt: -1 } }, listStoriesFacetPagination]).exec()
I tried grouping them like this (below) but i get at error saying that stories.groupBy is not a function, I'm stuck at this point and been trying to work this out for the past week.
const groupByUserId = stories.groupBy((userId: any) => {
return story.userId;
});
and it would not work.
You can achieve this by using reduce method, the code will be like this:
const list = [{
'name': 'John',
'userId': '1',
},
{
'name': 'Anne',
'userId': '2',
},
{
'name': 'John',
'userId': '1',
},
{
'name': 'Anne',
'userId': '2',
},
];
const groups = list.reduce((groups, item) => ({
...groups,
[item.userId]: [...(groups[item.userId] || []), item]
}), {});
This code will result in a object like this:
{
"1": [
{'name': 'John', 'userId': '1'},
{'name': 'John', 'userId': '1'}
],
"2": [
{'name': 'Anne', 'userId': '2'},
{'name': 'Anne', 'userId': '2'}
]
}
Hope it help you :D
Here is the solution i found,
const stories: any = await Story.StoryModel.aggregate([
{ $match: { '_id': { $in: combined } } },
{ $group: {
_id: '$userId',
stories: { $push: { url: '$url', _id: '$_id' , isLive: '$isLive', avatar: '$avatar', type:'$type', handle:'$handle', new:'$new', userName:'$userName', userId:'$userId', isDeleted:'$isDeleted', createdAt:'$createdAt' } } } },
{ $sort: { createdAt: 1 } },
listStoriesFacetPagination]).exec()

how can I add multiple travels information?

Here is my json data, I want to insert multiple travels information in travelers. Total numbers of travels may be given by the user.
In the below format I can just add one traveler.
return amadeus.booking.flightOrders.post(
JSON.stringify({
'data':{
'type': 'flight-order',
'flightOffers': [response.data.flightOffers[0]],
'travelers':[{
"id": 1,
"name": {
"firstName": req.body.firstname,
"lastName": req.body.lastname
},
"gender": req.body.gender,
"contact": {
"emailAddress": req.body.emailaddress,
"phones": [{
"deviceType": req.body.devicetype,
"countryCallingCode": req.body.countrycallingcode,
"number": req.body.number
}]
},
"documents": [{
"documentType": req.body.documentype,
"birthPlace": req.body.birthplace,
"issuanceLocation": req.body.issuancelocation,
"issuanceDate": req.body.issuancedate,
"number": req.body.p_number,
"expiryDate": req.body.expirydate,
"issuanceCountry": req.body.issuancecountry,
"validityCountry": req.body.validitycountry,
"nationality": req.body.nationality,
"holder": true
}]
}]
}
})
);
}).then(function (response)
travelers is an array. You can push multiple entries to it like
data.travelers.push(traveler);
You can run get multiple traveler details in your API like:
{
"travelers": [{
"firstname": "John",
"secondname": "Doe",
}, {
"firstname": "Jane",
"secondname": "Doe",
}]
}
This can then be looped over to push multiple travelers in the data variable.
let id = 1;
req.body.travelers.forEach(traveler => {
data.travelers.push({
id: id++,
name: {
firstName: traveler.firstname,
lastName: traveler.lastname
}
});
});

node js controller how to save data for array of objects

const mongoose = require('mongoose');
const addressSchema = mongoose.Schema({
type: String,
street: String,
city: String,
state: String,
country: String,
postalcode: Number
});
const createStudentSchema = mongoose.Schema({
admisionnum: Number,
first: String,
last: String,
phone: String,
address : [addressSchema],
isActive : { type : Boolean, default: true}
}, {
timestamps: true
});
module.exports = mongoose.model('createStudent', createStudentSchema);
Addreschema for address in array of objects . I am getting null in the output for the json below .
This is json input
{
"admisionnum":"1",
"first": "Dan",
"last": "HEllo",
"phone": "9000909575",
"address" : [
{
"type": "own",
"street": "18 ksdhks",
"city": "chennai",
"state": "Tamil Nadhu",
"country": "India",
"postalcode": "600097"
}
],
"isActive": "true"
}
Response Json output
{
"isActive": true,
"_id": "5c9e57f718e3de2ca4dd1d86",
"admisionnum": 1,
"first": "Jesus",
"last": "christ",
"phone": "9000909575",
"address": [
null,
null,
null,
null,
null,
null
],
"createdAt": "2019-03-29T17:37:59.291Z",
"updatedAt": "2019-03-29T17:37:59.291Z",
"__v": 0
}
Please help how to bind data for address . controller code is below
exports.createStudent = (req, res) => {
// Create a Note
const CreateStudent = new createStudent({
admisionnum: req.body.admisionnum,
first: req.body.first,
last: req.body.last,
phone: req.body.phone,
address : [
req.body.address.type,
req.body.address.street,
req.body.address.city,
req.body.address.state,
req.body.address.country,
req.body.address.postalcode
] ,
isActive: req.body.type
});
// Save Note in the database
CreateStudent.save()
.then(data => {
res.send(data);
}).catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while creating the Note."
});
});
};
Just use address : req.body.address, and it should work fine.
Since your address is an array and you are sending address array as well in the request, you don't need to do anything else.
Try this:
const CreateStudent = new createStudent({
admisionnum: req.body.admisionnum,
first: req.body.first,
last: req.body.last,
phone: req.body.phone,
address : req.body.address ,
isActive: req.body.type
});

Model not returning what is expected

I have 2 mongoose Models/Schemas (Products & Merchants). When doing a .find() on Products it is returning all products, as expected but when doing it for Merchants it is returning everything (both merchant and product data) when it should just be returning merchants based off the defined schema. I have one collection on my mongoDB server which contains all my merchants and the products.
Any idea what I am missing?
Thanks
Merchants Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MerchantShema = new Schema({
merchants: [{
merchant_id: Number,
price_current: Number,
price_rrp: Number,
aff_link: String,
merchant_product_id: Number,
aw_image_url: String,
cost_scoop: String,
created_at: Date,
updated_at: Date
}]
});
module.exports = mongoose.model('Merchants', MerchantShema, 'products');
Products Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new Schema({
ean: Number,
aw_product_id: Number,
product_name: String,
product_brand: String,
product_description: String,
img_sml: String,
img_lrg: String,
cat: String,
sub_cat: String,
weight: String,
rating: String,
created_at: Date,
updated_at: Date,
merchants: [{
merchant_id: Number,
price_current: Number,
price_rrp: Number,
aff_link: String,
merchant_product_id: Number,
aw_image_url: String,
cost_scoop: String,
created_at: Date,
updated_at: Date
}],
nutrition: [{
calories: Number,
protein: Number,
fat: Number,
sat_fat: Number,
carbs: Number,
sugar: Number,
salt: Number,
calories: Number
}],
ingredients: String,
flavours: String,
is_active: Boolean
});
module.exports = mongoose.model('Products', ProductSchema, 'products');
My Routes
app.get('/api/products', function(req, res) {
Products.find(function(err, products){
if (err) return console.error(err);
return res.send(products);
})
.where('is_active').equals('true')
});
app.get('/api/merchants', function(req, res){
Merchants.find(function(err, merchants){
if (err) return console.error(err);
return res.send(merchants);
});
});
Example of my collection
[
{
"_id": "55840f86e4b0ba19c15ee26d",
"merchant_id": "1111",
"merchant_aw_id": "1",
"merchant_name": "test merchant",
"merchant_url": "google.com",
"merchant_image": "",
"created_at": "",
"updated_at": "",
"merchants": []
},
{
"_id": "558426f9e4b0ba19c15ee495",
"ean": "123456789",
"aw_product_id": "55555",
"product_name": "Test Product",
"product_brand": "Test Brand",
"product_description": "This is a description for the test product",
"img_sml": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"img_lrg": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"cat": "Protein",
"sub_cat": "Protein",
"weight": "2.5kg",
"rating": "5",
"created_at": "",
"updated_at": "",
"nutrition": [
{
"salt": "1",
"sugar": "1",
"carbs": "1",
"sat_fat": "1",
"fat": "1",
"protein": "1",
"calories": "1"
}
],
"ingredients": "",
"flavours": "",
"is_active": "true",
"merchants": [
{
"merchant_id": 1111,
"price_current": 9.99,
"price_rrp": 15.99,
"aff_link": "google.com",
"merchant_product_id": 999,
"aw_image_url": "",
"cost_scoop": "43p",
"created_at": "",
"updated_at": ""
}
]
},
{
"ean": "123456789",
"aw_product_id": "55555",
"product_name": "Test Product",
"product_brand": "Test Brand",
"product_description": "This is a description for the test product",
"img_sml": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"img_lrg": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"cat": "Protein",
"sub_cat": "Protein",
"weight": "2.5kg",
"created_at": "",
"updated_at": "",
"nutrition": [
{
"salt": "1",
"sugar": "1",
"carbs": "1",
"sat_fat": "1",
"fat": "1",
"protein": "1",
"calories": "1"
}
],
"ingredients": "",
"flavours": "",
"is_active": "true",
"merchants": [
{
"merchant_id": 1111,
"price_current": 9.99,
"price_rrp": 15.99,
"aff_link": "google.com",
"merchant_product_id": 999,
"aw_image_url": "",
"cost_scoop": "43p",
"rating": "5",
"created_at": "",
"updated_at": ""
}
]
}
]
In looking at your merchants model definition. You are calling products in your export:
module.exports = mongoose.model('Merchants', MerchantShema, 'products');
This should probably read
module.exports = mongoose.model('Merchants', MerchantShema, 'merchants');
Another thing I noticed is that you have two keys called "calories".
I ran the code and it now brings back merchants correctly. However, when you call products, it brings back the merchant as part of that schema, since merchants are included in products. Another way you can do this is to use a nested schema. You can read about those in this other thread: Mongoose subdocuments vs nested schema
Hope that helps.

Resources