Dynamically Creating object keys - javascript

I've been trying to understand and master creating json objects with javascript, however I cannot seem to figure out how to (first iterate something, and use that value as my key). My second problem is when I see my json result, it always seems to be nested with a preceding blank item before it. Here is what I mean:
My current portion of code is:
.then((data)=>{
connection.query("SELECT * FROM amion_onCall", function (err, result, fields){
const fixed = [];
let i;
for (i in result){
aName = result[i].name;
aServ = result[i].specialty;
aShift = result[i].shift;
aOff = result[i].office;
aCell = result[i].cell;
aTag = result[i].tag;
var data = {aServ: {name:aName, service: aServ, shift: aShift, office: aOff, cell: aCell, tag: aTag}};
// console.log(data);
fixed.push(data);
}
fs.writeFile('./data/json/newAmion.json', JSON.stringify(fixed), function(err){
if (err) throw err;
console.log("Wrote New Amion");
});
});
})
The output in my json viewer is:
[
{
"aServ": {
"name": "Dr.John",
"service": "Cardiology",
"shift": "7a-7p",
"office": "123",
"cell": "123-456-789",
"tag": "no tags"
}
},
...and so on for my ~150 entries.
Problem #1: I want to move this up one full level. I'm not sure how to do that, or why it starts so deeply nested.
Problem #2: When I iterate aServ, I want the actual value to be output in the beginning of my json. My current code prints "aServ" statically for everyone...I don't want to do that. For example, this is how I am trying to get my json to output:
{
"Cardiology": {
"name": "Dr.John",
"service": "Cardiology",
"shift": "7a-7p",
"office": "123",
"cell": "123-456-789",
"tag": "no tags"
},
"Pulmonology": { ...and so on
}

Answer 1:
What do you mean by "preceding blank item"? Do you mean "aServe"? If yes, because you did it here var data = {aServ: { ... } }.
Also, you have a lot of items. So those are inside array [].
Answer 2:
// Change it to object instead of array
const fixed = {};
// Inside array
if (!Array.isArray(fixed[aServ])) {
fixed[aServ] = []
}
fixed[aServ].push({
name: aName,
service: aServ,
shift: aShift,
office: aOff,
cell: aCell,
tag: aTag,
})
No need to push item to array.
Remember, if there are multiple aServ with the same value then it will replace the existing item. That is why you should use an array.

Problem #1: I want to move this up one full level. I'm not sure how to do that, or why it starts so deeply nested.
It's nested because you're in an array of objects. Arrays in JavaScript are indicated by the surrounding brackets []. In this case I think it's what you want: you're creating an array of objects.
Problem #2: When I iterate aServ, I want the actual value to be output in the beginning of my json.
This line:
var data = {aServ: {name:aName, service: aServ, shift: aShift, office: aOff, cell: aCell, tag: aTag}}
Needs to be changed to this:
var data = {[aServ]: {name:aName, service: aServ, shift: aShift, office: aOff, cell: aCell, tag: aTag}}
Note the brackets. That will interpolate your variable values as an array key.

Related

How can I display different array values in react without getting map undefined?

This is the original data:
const myArray = [
'id': 'stuff', 'location': 'stuff2',
'phone_numbers'['stuff3','stuff4'], "address" : 'stuff5'
]
// so far, I'm getting the correct values back in an array from an API.
console.log(myReturnedArray) = [
{
"id": "10001",
"brand": "Best Brand",
"center_name": "Best Brand Texas",
"status": "Active",
"emails": [
{
"CreateDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"emailAddress": "test#test.com",
"firstName": "Test",
"lastName": "Tester",
"id": "0eac8839-6e61-42f5-b55f-e2fa17b0262b",
"licenseType": "Unlimited",
"updateDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"userType": "STORE"
}
],
"licenses": [
{
"CreateDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"licenseType": "STORE",
"status": "ASSIGNED",
"updatedBy": "SYSTEM",
"updateDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"renewDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"expirationDate": "October 12, 2022 at 10:59:09 AM UTC-5",
"id": "0eac8839-6e61-42f5-b55f-e2fa17b0262b"
}
]
}
]
*** whenever i try a map function i get the error "Objects are not valid as a React child (found: object with keys {id, brand, center_name, status, emails, licenses}). If you meant to render a collection of children, use an array instead." ***
I would like to display each value from my returned array in a div or span, but I keep getting errors like cannot get properties of undefined reading map, or a unique keys error whenever I try something.
// I would like to have each value from the object inside of myReturnedArray to use in my return statement.
return (
<span>your email is : "test#test.com", </span>
<div> your first name is : "Test" </div>
<span> your last name is : "lastName": "Tester", </span>
);
Anytime I try and use a map function like this in my return statement:
{ myReturnedArray.map(item => <div>{item.name}</div>) }
It returns myReturnedArray is undefined. But when I do:
{ JSON.stringify(myReturnedArray) }
It renders returnedArray as a string correctly. So I know the return method has access to the array; I just can't display it.
You don't have a name property in your array items.
Here is an example of code with your data that displays its content properly:
https://codesandbox.io/s/vigorous-euclid-nzbcp0?file=/src/App.js:24-283
Final solution: codeSandbox
Explantion to the errors you got:
1: The data structure you updated is very complex and nested with object inside array and arrays inside this object and so on. So, of course it will throw an error "Objects are not valid as a React child".
You can't put an entire object between div tags, You need to map this object fields one by one to have single values between each div.
2: About the "unique key" issue - this is a warning, not an error. It's always showing this warning when you map object items to elements without adding the key attribute to each item.
So in order to get rid of this warning, Just add the key attribute to the divs that are returned inside a map function, and choose some uniqe key.
How can you map it like this?
As I understood, The structure you have is one big array - myReturnedArray, and in this array you will have many(now you have just one) objects when each one contains:
An emails array which contains object(s).
An licenes array which contains object(s).
Some other key:value pairs.
In order to map myReturnedArray correctly - You'll need a ForEach loop that will map every big object inside of it, and then return all the mapped objects together.
First, I created an helper function that maps an array of objects(without nested arrays or something) to HTML div tags.
And I will use this function in order to map the emails and licenes arrays.
Helper function:
const mapArrayOfObjects = (array) => {
const arrayAsDivs = array.map((obj, index) => {
const mappedObj = Object.entries(obj).map(([key, value]) => {
return <div key={key}>{key + ' : ' + value}</div>;
});
return (
//Returns a div with one object of the array and space after it.
<div key={'nestedObj' + index}>
{mappedObj}
<br />
</div>
);
});
return arrayAsDivs; //The function returns ALL the mapped objects in the array.
};
It looks complex, but all it does is going through the array, and mapping each object to a big div tag with all the key:value pairs as nested divs. (And I added the br to have some space between the objects. (In your case you have just one object in the emails, but I assume that there would more.)
Using forEach
In this function, I map all the big objects that are inside myReturnedArray:
const allObjectsHTML = [];
myReturnedArray.forEach((obj) => {
const emailsAsDivs = mapArrayOfObjects(obj.emails);
const licensesAsDivs = mapArrayOfObjects(obj.licenses);
const otherFields = Object.entries(obj).map(([key, value]) => {
if (!Array.isArray(value)) {
return <div key={key}>{key + " : " + value}</div>;
}
});
const objectAsHTML = (
<div>
<div>{otherFields}</div>
<div>
<h3>Emails:</h3>
{emailsAsDivs}
</div>
<div>
<h3>Licenses:</h3>
{licensesAsDivs}
</div>
</div>
);
allObjectsHTML.push(objectAsHTML);
});
What this function does in each iteration:
Use the helper function to map the emails,licenses arrays.
Map the rest of the key:value pairs in the object.
Push the mapped object to the allObjectsHTML array that will contain all the mapped objects.
And for the last step
Now all you need to do is that in your JSX code you return:
return (
<>
{allObjectsHTML.map((obj,index) => (
<div key={"bigObj"+index}>{obj}<hr/></div>
))}
</>
);
This returns a mapped version of the allObjectsHTML.
This is the codeSandbox of my code.
And in case you want to check if it works on many objects in your array: second codeSandbox.
Note: If you know for sure that you have just one object in the myReturnedArray - then you don't need to use forEach. See this code.
The initial format of your data is flawed, it's not a JS syntax. To get it done properly first you have to make it a proper data container. For this kind of task you don't need arrays, you have an object for that.
const data = {
id: 'stuff',
location: 'stuff2',
address: 'stuff5',
phone_numbers: ['stuff3','stuff4']
}
Then in your React Components return section you may ve it done like this:
const {id, location:dataLoc, address, phone_numbers:phNums} = data
const [num1, num2] = phNums
return (
<div>{dataLoc}</div>
<span>{address}</span>
//etc
)
I also reformatted yopur code a bit to meet the JS naming conventions. We use camelCase here, so no phone_numbers (snake_case is for Py)but phNum.

Adding a new object into a nested array

I want to add a new object for each nested array. I'm calling this function any time I add a product to my orderintake:
add2order(productID, productName, productRatePlans) {
this.orderIntake.push({ productID, productName, productRatePlans });
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
this is an example response from the server:
{
"id": "8adc8f996928b9a4016929c59b943a8f",
"sku": "SKU-00006778",
"Partner_Account_ID__c": null,
"productRatePlans": [
{
"id": "8adce4216928c28d016929c59bff3372",
"status": "Active",
"name": "Enterprise",
"description": null,
"effectiveStartDate": "2016-02-26",
"effectiveEndDate": "2029-02-26",
"productRatePlanCharges": [
{
"id": "8adc8f996928b9a4016929c59d183a92",
"name": "USAGE_COUNTER_2",
"type": "Usage",
"model": "Volume",
"uom": "Each",
"pricingSummary": [
"Up to 5000 Each: USD0 flat fee"
],
"pricing": [
{
...
}
],
"defaultQuantity": null,
"applyDiscountTo": null,
"discountLevel": null,
"discountClass": null,
...
"financeInformation": {
..,
}
}
]
}
],
"productFeatures": [
{
...
}
]
}
The data is being retrived this way from an external REST backend so unfortunately I can't initialize the data including the new property...
so in every productRatePlanCharges there should be 1 new object 'quantity'.
How can I add this field to every productRatePlanCharges?
Right now I'm getting: ERROR
TypeError: Cannot read property 'productRatePlanCharges' of undefined
And how can I make sure I'm always adding this to the last orderIntake element? Don't mind productRatePlans there is only 1 in each orderintake...
thanks for your support!
Here you have to create productDetails object with inititalised array like below so that you won't get the error.
add2order(productID, productName, productRatePlans) {
// Create object like below
let productDetails = { productID : productID, productName : productName, productRatePlans : productRatePlans
}
this.orderIntake.push(productDetails);
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
Hope this will help!
as you used Angular you probably use Typescript too. I recommend that you create a model like your incoming model and there define your quantity: number inside productRatePlanCharges object. then map the incoming data to your own model. therefore you will have a quantity=0 in your model that you can change it later in a loop.
If you want to continue with your own way take a look at this:
Add new attribute (element) to JSON object using JavaScript
there is no problem to add an element to current model almost like you did, and the problem might be somewhere else as your error refers to existence of productRatePlanCharges!
as you used forEach I prefer to use that 'element' and double iterating with i++; is not a good idea to me.
this might be better:
element.quantity = element.defaultQuantity;

Array inside object | database insertion

I have the following array of objects. Currently it have one object containing several inside of it.
let arr =
[
{
"data": {
"Score": {
"score": [
"87",
"21"
],
"Player": [
"Wiki",
"Tim"
]
},
"Designation": {
"By": [
"0",
"0",
"1",
"0",
"0"
],
"Position": [
"31/07/17",
"31/07/17",
"31/07/17",
"31/07/17",
"31/07/17"
]
},
"Address": {
"Location": "London",
"House_No": "43-B",
}
}
}
]
The above data will go in one table.
I have tried looping it and inserting but did't got any way out. The above data is not constant means will change like Position have 5 elements, It can be 6 next time, So i cannot simply insert it via its indexes.
I have tried things but no success.
Mysql can store json data, and you can parse after you fetch, even you can parse json data from mysql queries but thats little complex if data changes, so its better to store it, fetch and parse.
You can select feild type JSON and store json in it.
CREATE TABLE `book` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL,
`tags` json DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
you can insert json data in it by using php function:-
$json_data = json_encode($json_data);
insertion command will be:-
INSERT INTO `book` (`title`, `tags`)
VALUES (
'ECMAScript 2015: A SitePoint Anthology',
'$json_data'
);
For manipulating json data via mysql queries there are several function like JSON_ARRAY(), JSON_OBJECT() and so on, which you can prefer to use. Please refer to below article for details:-
https://www.sitepoint.com/use-json-data-fields-mysql-databases/
In Mongodb if you have dynamic data you can use mixed type schema like below:-
details:Schema.Types.Mixed,
Sample schema:-
// grab the things we need
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongoosePaginate = require('mongoose-paginate');
// create a schema
var casesSchema = new Schema({
sku: {type:String, unique:true},
details:Schema.Types.Mixed,
created_at: {type:Date, default: Date.now},
images: Schema.Types.Mixed,
ebay_hosted_images: Schema.Types.Mixed,
cloudinary_hosted_images: Schema.Types.Mixed,
dropbox_hosted_images: Schema.Types.Mixed,
is_listed:Boolean,
user_id : {type: String, ref:'User'}
});
casesSchema.plugin(mongoosePaginate);
var cases = mongoose.model('cases', casesSchema);
module.exports = cases;
In ES6 you can simply get all keys and value of an object like this:Object.keys(myObj).forEach(key => {
console.log(key); // the name of the current key.
console.log(myObj[key]); // the value of the current key.
});
If it is an array for each use to get the all values
arr.forEach(function(element) {
console.log(element);
});
arr.push(element) is used to push the element to as last index of array.

Update object with given ID embed in array without restructuring Mongo database

I've got the following document named "clients" which includes id, name and list of projects (array of objects):
{
"_id": {
"$oid": "572225d997bb651819f379f7"
},
"name": "ppg",
"projects": [
{
"name": "aaa",
"job_description": "",
"projectID": 20
},
{
"name": "bbbb",
"job_description": "",
"projectID": 21
}
]
}
I would like to update "job_description" of project with given "projectID" like this:
module.exports.saveJobDesc = function(client, idOfProject, textProvided) {
db.clients.update({ name: client},
{ $set: {'projects.0.job_description': textProvided }});
};
But instead of hardcoded index "0" of array I want to find specific project using "projectID". Is there a way to achieve this without changing the structure of collection and/or document?
If you want to update the "job_description" where name="ppg" and project_id=20 then you can use below mongo query:-
db.clients.update({ "name":"ppg","projects.projectID":20 },{$set: {"projects.$.job_description": "abcd"}})
Please let me know if any thing else is required
You cannot update multiple array elements in single update operation, instead you can update one by one which takes time depends upon number of elements in array and number of such documents in collection. see New operator to update all matching items in an array
db.test2.find().forEach( function(doc) {
var projects = doc.projects;
for(var i=0;i<projects.length;i++){
var project = projects[i];
if(project.projectID == 20){
var field = "projects."+i+".job_description";
var query = {};
query[field] = "textasdsd";
db.test2.update({ _id: doc._id},{ $set:query});
}
}
})

lunr.js Add data about an index record

In lunr.js, you can add a unique reference using the .ref() method but I can't find any method to add extra data/info about that particular record. Is it not possible or am I missing something really obvious.
I even tried assigning an object to ref but it saves it as a string.
EDIT
For now I am saving all the contents as a JSON string in .ref(), which works but is really ugly to use.
lunr does not store the documents that you pass it to index at all, the way it indexes means that the original document is not available to lunr at all, so there is no way of passing and storing meta data associated with the indexed object.
A better solution is to keep your records outside of lunr, and use the reference you give to lunr to pull out the record when you get the search results. That way you can store whatever arbitrary meta data you want.
A simple implementation might look like this, its overly simplistic but you get the idea...
var documents = [{
id: 1,
title: "Third rock from the sun",
album: "Are you expirienced",
rating: 8
},{
id: 2,
title: "If 6 Was 9",
album: "Axis bold as love",
rating: 7
},{
id: 3,
title: "1983...(A Merman I Should Turn to Be)",
album: "Electric Ladyland",
rating: 10
}]
var db = documents.reduce(function (acc, document) {
acc[document.id] = document
return acc
}, {})
var idx = lunr(function () {
this.ref('id')
this.field('title', { boost: 10 })
this.field('album')
})
documents.forEach(function (document) {
idx.add(document)
})
var results = idx.search("love").forEach(function (result) {
return db[result.ref]
})

Categories