JavaScript array - push multi dimensional array - javascript

I have an array like this:
message_list = [
{
"Main_body": "test msg",
"emp_name": "test",
"emp_salary": "5000 USD"
}
]
Its length (e.g., message_list.length) is 1.
Now I have another array like this:
added_user_data = [
{
"PostSharedLog": {
userids: "2,4,5"
},
"created": "2123123"
},
{
"PostSharedLog": {
userids: "3,1"
},
"created": "2123147"
}
]
Its length (added_user_data.length) is 2.
I want to push the above array added_user_data into message_list.
I tried doing it inside a for loop, now since the length of message_list is 1, for the second iteration, the values do not get pushed since message_list[1] does not exist and is undefined. But I still want to create message_list[1] even if it does not exist.
if i do the below :
for(var k =0;<count(added_user_data.length);k++)
{
message_list[k].PostSharedLog = added_user_data[k].PostSharedLog ;
}
It only appends the first row from the array added_user_data and gives an output like this when i print out message_list :
[{
"Main_body": "test msg",
"emp_name": "test",
"emp_salary": "5000 USD",
"PostSharedLog": {
userids: "2,4,5"
} }]
The second iteration does not append anything at all .
I would like to see the below :
[{
"Main_body": "test msg",
"emp_name": "test",
"emp_salary": "5000 USD",
"PostSharedLog": {
userids: "2,4,5"
},
"PostSharedLog": {
userids: "3,1"
}
}]

JSON objects can not have duplicate keys.
A JSON object is basically a Map it has keys and values. Each key in an object must be unique.
Invalid JSON
What you posted as your desired outcome can never exist because PostSharedLog can only exist once. Setting it again just changes the value.
Also userids is not a valid JSON key, it should be wrapped with " always!
Any JSON linter will show you exactly why this is.
{
"Main_body": "test msg",
"emp_name": "test",
"emp_salary": "5000 USD",
"PostSharedLog": {
userids: "2,4,5"
},
"PostSharedLog": {
userids: "3,1"
}
}
What you probably need to do is something like:
{
"MainBody": "test msg",
"EmployeeName": "test",
"EmployeeSalary": { "amount": 5000, "currency": "USD" },
"PostSharedLog": {
"UserIds": [2,4,5,3,1]
}
}
NOTES:
Your names are not consistent. Really? Every one of them is a different format?
Do not abbreviate.
Do not store multivalue fields in String types, use a real Array! [1,2,3,4] instead of "1,2,3,4"
Do not store mutlivalue fields in String types, use a real Object! { amount: 5000, currency: "USD" } instead of "5000 USD"

Related

Query for only a single document based on key name in MongoDB

I am working on a MERN project. I have created a collection in MongoDB having different types of document. Is it an accepted practice to have different structure documents in a single collection? Secondly i need to fetch only a single document from the collection using the key name. My documents are
[{
"_id": {
"$oid": "6333f72822dc0acc4bea17bd"
},
"designation": [
{
"name": "Chairman",
"level": 17
},
{
"name": "Director",
"level": 13
},
{
"name": "Secretary ",
"level": 13
},
{
"name": "Account Officer",
"level": 9
},
{
"name": "Data Entry Operator-GR B",
"level": 5
}
]
},
{
"_id": {
"$oid": "6334313b22dc0acc4bea17c2"
},
"storeRole": ["manager", "approver", "accepter", "firstsignatory"]
},
{
"_id": {
"$oid": "63369d2083a7cc2e818990dd"
},
"designationSuffix": ["I","II", "III"]
}]
How do I get any of the three documents if I only know the key name i.e(designation, storeRole, designationSuffix). I dont want to use ID value.
Welcome to SO.
First, yes it is an accepted practice and indeed, a powerful feature of MongoDB to have different shapes of data in a single collection.
There are two important things to remember when querying for data:
Matching on fields that don't even exist in a document is OK; the document will simply be skipped. This permits you, for example, to query for storeRole and ignore the other documents with designation, etc. -- unless of course you wish to look for those too using an $or expression.
Matching (using $match) for elements in an array will return the whole array, not just the elements that match.
To illustrate this point, let's expand your input data slightly:
{"designation": [
{"name": "Chairman","level": 17},
{"name": "Director", "level": 13}
]
},
{"designation": [
{"name": "Secretary","level": 13}
]
},
We will use dot notation to reach into the structures in the designation array to find those docs where at least one of the name fields is Chairman:
db.foo.aggregate([
{$match: {"designation.name": "Chairman"}}
]);
{
"_id" : 0,
"designation" : [
{
"name" : "Chairman",
"level" : 17
},
{
"name" : "Director",
"level" : 13
}
]
}
The query eliminated the document with name = Secretary as expected but properly returned the whole document (and the whole array) where name = Chairman. Very often the goal is to fetch only the matching items in the array; this is accomplished with the $filter operator:
db.foo.aggregate([
{$match: {"designation.name": "Chairman"}},
{$project: {
// Assigning the output of $filter to the same name as input:
designation: {$filter: {
input: "$designation",
as: "zz",
cond: {$eq: ['$$zz.name','Chairman']}
}}
}}
]);
{
"_id" : 0,
"designation" : [
{
"name" : "Chairman",
"level" : 17
}
]
}
An alternative approach which is useful when query conditions yield null or empty arrays instead of eliminating the document altogether is to $filter first, then match only on results where the array has a length > 1. We must use the $ifNull function to protect $size from being passed a null by turning it into an empty (but not null) array:
db.foo.aggregate([
{$project: {
// Assigning the output of $filter to the same name as input:
designation: {$filter: {
input: "$designation",
as: "zz",
cond: {$eq: ['$$zz.name','Chairman']}
}}
}},
{$match: {$expr: {$gt:[{$size: {$ifNull:["$designation",[] ]}}, 0]}} }
]);
Try commenting out the $match to see what $filter returns when a document has the target array field but no matches vs. when the document does not have the field.

How can I loop over a multi level JSON object and create a new Javascript object from one of it's key and values

I have a JSON object that looks like the following
{
"venue": {
"time1": [
{
"Status": "Available"
},
{
"Status": "Unavailable"
},
{
"Status": "Unavailable"
}
],
"time2": [
{
"Status": "Available"
},
{
"Status": "Available"
},
{
"Status": "Unavailable"
}
]
}
}
I want to loop over this object and create a new object that has the times as the key and an array of status' as it's values. So the new object would look like the following...
{
"time1": ["Available", "Unavailable", "Unavailable"],
"time2": ["Available", "Available", "Unavailable"]
}
NB: I'm struggling with this, because i can't manage to reach the array. I have tried various maps, reduce etc. but with no joy, and I can't seem to find the right answer on SO because, I'm not sure what to search for.
Run a reduce over object's key-value pairs to get the desired result.
Here is a snippet for your reference. Comments are inline
const obj = {
venue: {
time1: [{Status: "Available"},{Status: "Unavailable" },{Status: "Unavailable" }],
time2: [{Status: "Available" },{Status: "Available" },{Status: "Unavailable" }]
}
};
const result = Object.entries(obj.venue).reduce((acc, element) => {
// Destrcuture key, values here
const [key, status] = element;
// Run a map to fetch the status and then assign it to the key
acc[key] = status.map((item) => item.Status);
return acc;
}, {});
console.log(result);
The JavaScript Object obj.venue is converted into an array (Object.entries(obj.venue)), each of their timeX arrays is then processed (get the Status-value of each object) and eventually it is converted back into an object again using Object.fromEntries().
All this can be done in a single line of code:
const obj= {venue: {time1: [{Status: "Available"},{Status: "Unavailable"},{Status: "Unavailable"}],
time2: [{Status: "Available"},{Status: "Available"},{Status: "Unavailable"}]} };
const res=Object.fromEntries(Object.entries(obj.venue).map(([k,v])=>[k,v.map(st=>st.Status)]));
console.log(obj); // original object remains unchanged
console.log(res);
const a = Object.values(your_object)[0];
a['time1'] = a['time1'].flatMap(x=>Object.values(x))
a['time2'] = a['time2'].flatMap(x=>Object.values(x))
console.log(a)
/*
{
time1: [ 'Available', 'Unavailable', 'Unavailable' ],
time2: [ 'Available', 'Available', 'Unavailable' ]
}
*/
POJO (Plain old javascript object) cannot be iterated: Iterable Objects
The only solution is to read the object entries and then access the internal array. However, note that iterating over object does not guarantee that the order is maintained SO discussion
That said, you can use any of the object iterable methods ["keys", "values", "entries"] to access the inner data.
Using entries()
Object.entries(jsonObj.venue).map(entry => console.log(entry))
hope this code helping you
var json= {
"venue": {
"time1": [
{
"Status": "Available"
},
{
"Status": "Unavailable"
},
{
"Status": "Unavailable"
}
],
"time2": [
{
"Status": "Available"
},
{
"Status": "Available"
},
{
"Status": "Unavailable"
}
]
}
}
Object.keys(json.venue).map((obj,index)=>json.venue[obj] = json.venue[obj].flatMap(ele=>Object.values(ele)),[])
console.log(json)

Adding fulfilment code to make a cart for order bot. gives me undefined on quantity parameter

the function below prints the item and in what quantity that has been ordered
function confirmitem(agent){
const item = agent.getContext('item'),
Food = item.parameters.Food,
quantity = item.parameters.quantity;
agent.add('Confirming '+Food+' in a quantity of '+quantity);
}
below is the output context
"outputContexts": [{
"name": "projects/simple-dialog-wtckcj/agent/sessions/1a459958-2249-5973-9561-5418940b0b22/contexts/item",
"lifespanCount": 4,
"parameters": {
"Food": "matooke",
"Food.original": "matooke",
"quantity": {
"number.original": "1",
"number": 1
},
"quantity.original": "1"
}
},
{
"name": "projects/simple-dialog-wtckcj/agent/sessions/1a459958-2249-5973-9561-5418940b0b22/contexts/itemconfirm",
"lifespanCount": 4,
"parameters": {
"quantity": {
"number": 1,
"number.original": "1"
},
"quantity.original": "1",
"Food": "matooke",
"Food.original": "matooke"
}
}
]
the actual output is
'Confirming matooke in a quantity of [object Object]'
The issue is that item.parameters.quantity is an object with a value of
{
"number.original": "1",
"number": 1
},
When you try to print this, the normal way to print the object is just with "[object Object]", as you've noticed.
You probably want to access the "number" field inside this object with something like item.parmeters.quantity.number. If you wanted to access the "original" value, which is exactly what the user said, you may need to use something like item.parameters["quantity.original"]. You would need to use this indexing method because "quantity.original" contains a period.

How to get all values of given specific keys (for e.g: name) without loop from json?

I want to fetch all the names and label from JSON without loop. Is there a way to fetch with any filter method?
"sections": [
{
"id": "62ee1779",
"name": "Drinks",
"items": [
{
"id": "1902b625",
"name": "Cold Brew",
"optionSets": [
{
"id": "45f2a845-c83b-49c2-90ae-a227dfb7c513",
"label": "Choose a size",
},
{
"id": "af171c34-4ca8-4374-82bf-a418396e375c",
"label": "Additional Toppings",
},
],
},
]
}
When you say "without loops" I take it as without For Loops. because any kind of traversal of arrays, let alone nested traversal, involve iterating.
You can use the reduce method to have it done for you internally and give you the format you need.
Try this :
const data = {
sections: [
{
id: "62ee1779",
name: "Drinks",
items: [
{
id: "1902b625",
name: "Cold Brew",
optionSets: [
{
id: "45f2a845-c83b-49c2-90ae-a227dfb7c513",
label: "Choose a size"
},
{
id: "af171c34-4ca8-4374-82bf-a418396e375c",
label: "Additional Toppings"
}
]
}
]
}
]
};
x = data.sections.reduce((acc, ele) => {
acc.push(ele.name);
otherName = ele.items.reduce((acc2, elem2) => {
acc2.push(elem2.name);
label = elem2.optionSets.reduce((acc3, elem3) => {
acc3.push(elem3.label);
return acc3;
}, []);
return acc2.concat(label);
}, []);
return acc.concat(otherName);
}, []);
console.log(x);
Go ahead and press run snippet to see if this matches your desired output.
For More on info reduce method
In the context of cJSON
yes, we can fetch the key value for any of the object.
1 - each key value is pointed by one of the objects. will simply fetch that object and from there will get the key value.
In the above case for
pre-requisition: root must contain the json format and root must be the cJSON pointer. if not we can define it and use cJSON_Parse() to parse the json.
1st name object is "sections" will use
cJSON *test = cJSON_GetObjectItem(root, "sections");
char *name1 = cJSON_GetObjectItem(test, "name" )->valuestring;
2nd name key value
cJSON *test2 = cJSON_GetObjectItem(test, "items");
char *name2 = cJSON_GetObjectItem(tes2, "name")->valuestring;
likewise, we can do for others as well to fetch the key value.

How to sort an array of objects in ascending order of number?

I have an array of objects like the following :
var array = {
"112" : {
"id": "3",
"name": "raj"
},
"334" : {
"id": "2",
"name": "john"
},
"222" : {
"id": "5",
"name": "kelvin"
}
}
Now i want to sort the array in ascending order of id and then restore it in array. I tried using sort() but could not do it. Please help how to do so that when i display the data from the array it comes sorted.
Assuming you meant your code to be an array of objects, ie:
var unsortedArray = [
{ id: 3, name: "raj" },
{ id: 2, name: "john" },
{ id: 5, name: "kelvin" }
];
Then you would be able to sort by id by passing a function to Array.sort() that compares id's:
var sortedArray = unsortedArray.sort(function(a, b) {
return a.id - b.id
});
As others have pointed out, what you have is an object containing objects, not an array.
var array = {
"112" : {
"id": "3",
"name": "raj"
},
"334" : {
"id": "2",
"name": "john"
},
"222" : {
"id": "5",
"name": "kelvin"
}
}
var sortedObject = Array.prototype.sort.apply(array);
result:
{
"112": {
"id": "3",
"name": "raj"
},
"222": {
"id": "5",
"name": "kelvin"
},
"334": {
"id": "2",
"name": "john"
}
}
That isn't an array, it is an object (or would it if it wasn't for the syntax errors (= should be :)). It doesn't have an order.
You could use an array instead (making the current property names a value of a key on the subobjects).
Alternatively, you could use a for loop to build an array of the key names, then sort that and use it as a basis for accessing the object in order.
JavaScript objects are unordered by definition. The language specification doesn't even guarantee that, if you iterate over the properties of an object twice in succession, they'll come out in the same order the second time.
If you need things to be ordered, use an array and the Array.prototype.sort method.
That is an object but you can sort an array ilke this:
Working Demo: http://jsfiddle.net/BF8LV/2/
Hope this help,
code
function sortAscending(data_A, data_B)
{
return (data_A - data_B);
}
var array =[ 9, 10, 21, 46, 19, 11]
array.sort(sortAscending)
alert(array);​
Not many people knows that Array.sort can be used on other kinds of objects, but they must have a length property:
array.length = 334;
Array.prototype.sort.call(array, function(a, b) {return a.id - b.id;});
Unfortunately, this doesn't work well if your "array" is full of "holes" like yours.

Categories

Resources