Related
I have the following array of objects:
[{
idChatPublic: "1",
message: "hello",
chatLike: [{
id: "1",
idChatPublic: "1"
}]
}]
What I want is simply add a new object into chatLike array.
Here is my attempt, but it doesn't seem to be working whats wrong with this piece of code?
async function sendLike(messageId: string) {
const newLike = {
idChatPublic: messageId,
}
mutateMessages(
(data) => {
console.log(data) // returns the array I want to update
data.map((message) => {
if (message.idChatPublic === messageId) {
console.log(message.chatLike) // returns the array inside the object I want to update
return {
...message,
chatLike: [...message.chatLike, newLike]
}
} else {
return message
}
})
}
)
}
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Probably, you have to create const with new array and return it:
const newData = data.map((message) => {
if (message.idChatPublic === messageId) {
console.log(message.chatLike) // returns the array inside the object I want to update
return {
...message,
chatLike: [...message.chatLike, newLike]
}
} else {
return message
}
});
return newData;
const data = [
{
idChatPublic: "1",
message: "hello",
chatLike: [
{
id: "1",
idChatPublic: "1",
},
],
},
];
function updateChatLike() {
return data.map((d) => {
return {
...d,
chatLike: [
...d.chatLike,
{
id: 2,
idChatPublic: "2",
},
],
};
});
}
console.log(JSON.stringify(updateChatLike(), null, 4));
I have used JSON.stringify() to log complete nested object
Output
[
{
"idChatPublic": "1",
"message": "hello",
"chatLike": [
{
"id": "1",
"idChatPublic": "1"
},
{
"id": 2,
"idChatPublic": "2"
}
]
}
]
You don't need map(). I think you can do that like this:
async function sendLike(messageId: string) {
const newLike = {
idChatPublic: messageId,
};
mutateMessages((data) => {
data.forEach((message) => {
if (message.idChatPublic === messageId) {
message.chatLike.push(newLike);
}
}
});
}
Loop throw your objects array with forEach() and if the id will match you can update chatLike array with push() to add a new newLike object.
Map is not necessary here in your case.
Try this.
const data = [{
idChatPublic: "1",
message: "hello",
chatLike: [{
id: "1",
idChatPublic: "1"
}]
}];
console.log("before " , data);
sendLike(1);
console.log("after " , data);
function sendLike(messageId) {
const newLike = {
idChatPublic: messageId,
}
// mutateMessages((data) => {
data.forEach((message) => {
//console.log(message.idChatPublic);
if (message.idChatPublic == messageId) {
message.chatLike.push(newLike);
}
});
//});
}
I have a Json data that I want to have in a different format.
My original json data is:
{
"info": {
"file1": {
"book1": {
"lines": {
"102:0": [
"102:0"
],
"105:4": [
"106:4"
],
"106:4": [
"107:1",
"108:1"
]
}
}
}
}
}
And I want to map it as following:
{
"name": "main",
"children": [
{
"name": "file1",
"children": [
{
"name": "book1",
"group": "1",
"lines": [
"102",
"102"
],
[
"105",
"106"
],
[
"106",
"107",
"108"
]
}
],
"group": 1,
}
],
"group": 0
}
But the number of books and number of files will be more. Here in the lines the 1st part (before the :) inside the "" is taken ("106:4" becomes "106"). The number from the key goes 1st and then the number(s) from the value goes and make a list (["106", "107", "108"]). The group information is new and it depends on parent-child information. 1st parent is group 0 and so on. The first name ("main") is also user defined.
I tried the following code so far:
function build(data) {
return Object.entries(data).reduce((r, [key, value], idx) => {
//const obj = {}
const obj = {
name: 'main',
children: [],
group: 0,
lines: []
}
if (key !== 'reduced control flow') {
obj.name = key;
obj.children = build(value)
if(!(key.includes(":")))
obj.group = idx + 1;
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
The group information is not generating correctly. I am trying to figure out that how to get the correct group information. I would really appreciate if you can help me to figure it out.
You could use reduce method and create recursive function to build the nested structure.
const data = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}}
function build(data) {
return Object.entries(data).reduce((r, [key, value]) => {
const obj = {}
if (key !== 'lines') {
obj.name = key;
obj.children = build(value)
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
I couldn't understand the logic behind group property, so you might need to add more info for that, but for the rest, you can try these 2 functions that recursively transform the object into what you are trying to get.
var a = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}};
var transform = function (o) {
return Object.keys(o)
.map((k) => {
return {"name": k, "children": (k === "lines" ? parseLines(o[k]) : transform(o[k])) }
}
)
}
var parseLines = function (lines) {
return Object.keys(lines)
.map(v => [v.split(':')[0], ...(lines[v].map(l => l.split(":")[0]))])
}
console.log(JSON.stringify(transform(a)[0], null, 2));
I want create key array which value is "str"
I have following nested json:
[
{
"Attr": [
{
"power": { "p1": "str", "t3": "str" },
"light": [
{"test": "str"},
{"test2": [ { "t4": "str" }]}
]
}
]
},
{
"Attr1": [
{
"power1": { "p2": "str", "t5": "str" },
"light1": [
{ "test3": "str" },
{ "test_x": [
{ "t_x": "str" },
{ "t_y": [
{ "t_y1": "str" }
]
}
]
}
]
}
]
}
]
I want to create array of key where key value is "str",
I want get following array output:
["p1", "t3", "test", "p2", "t5", "test3", "t_x", "t_y1"]
How to create key array from nested JSON by particular value?
IMHO, you are looking for something like this perhaps:
var testArr = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];
var strFind = (arr, accumulator = []) => {
arr.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
if (value === "str") accumulator.push(key);
if (Array.isArray(value)) strFind(value, accumulator);
if (key.includes("power")) {
Object.entries(value).forEach(([cKey, cValue]) => {
if (cValue === "str") accumulator.push(cKey);
})
}
});
})
return accumulator;
}
console.log(strFind(testArr));
If you can write an recursive function that would be best for performance.
But if you want to skip the recursive calling with (for each keys in a nested object), then you can try JSON.parse with additional parameter (callback) which will be called recursively by it. as a generic solution, I am adding a snippet (with JSON.parse, assuming helping on writing a recursive function should not be entertained / part of this answer).
But remember, IF you are bothered about performance efficiency you should not use this as you have to stringify (may be a large object) and again parse. But, if you have a JSON string, it should be one of the best solution.
var anyObject = [
{
"Attr": [
{
"power": { "p1": "str", "t3": "str" },
"light": [
{"test": "str"},
{"test2": [ { "t4": "str" }]}
]
}
]
},
{
"Attr1": [
{
"power1": { "p2": "str", "t5": "str" },
"light1": [
{ "test3": "str" },
{ "test_x": [
{ "t_x": "str" },
{ "t_y": [
{ "t_y1": "str" }
]
}
]
}
]
}
]
}
]
function getKeys(obj, str) {
let resultArr = [];
JSON.parse(JSON.stringify(obj), (key, val) => {
if(val === str) { resultArr.push(key) }
return val;
} )
return resultArr;
}
console.log(getKeys(anyObject, 'str'))
This is not case specific, you can have all the keys if you pass another callback in JSON.parse and also can transform the object using this (returning transformed value instead the actual value)
And if you want to use lodash to iterate the object recursively, then you can use
_.cloneDeepWith for iterating the object recursively.
Here is a Working example:
let anyObject = [
{
"Attr": [
{
"power": { "p1": "str", "t3": "str" },
"light": [
{"test": "str"},
{"test2": [ { "t4": "str" }]}
]
}
]
},
{
"Attr1": [
{
"power1": { "p2": "str", "t5": "str" },
"light1": [
{ "test3": "str" },
{ "test_x": [
{ "t_x": "str" },
{ "t_y": [
{ "t_y1": "str" }
]
}
]
}
]
}
]
}
];
function getKeys(obj, str) {
let resultArr = [];
_.cloneDeepWith(obj, (value, key) => { value === 'str' && resultArr.push(key)});
return resultArr;
}
console.log(getKeys(anyObject, 'str'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Here's yet another possibility, exploiting the naturally recursive nature of JSON.stringify:
const input = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];
const output = [];
JSON.stringify(input, (key, val) => {
if (val === 'str') output.push(key);
return val;
});
console.log(output);
Try something like this:
var array = [];
function searchForStringInJsonRecursive (jsonData, str) {
for(var i in jsonData) {
// If the element is an Array or nested object continue to search
if (typeof jsonData[i] === 'object') {
searchForStringInJsonRecursive(jsonData[i], str);
}
// If the element is not an Object and matches str add the it to the array
else if (jsonData[i] === str) {
array.push(i);
}
}
}
Assuming your json is in a variable called data you can call the function like this:
searchForStringInJsonRecursive(data, 'str');
array will then contain all the keys which content matched 'str'
Another try using JSON.stringify and string parsing:
const result = JSON.stringify(data)
.match(/"[^"]+":"str"/g) // get all "xxx":"str" pairs
.map(r => r.substring(1, r.indexOf(':') - 1)); // pick out all "xxx"
console.log(result);
// ["p1", "t3", "test", "t4", "p2", "t5", "test3", "t_x", "t_y1"]
Here's one way using lodash:
var testArr = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];
var findStr = function(o) {
return _(o)
.map(function(v, k) {
return v === 'str'
? k
: _.isObject(v) ? findStr(v) : null;
})
.compact()
.flatten()
.value();
};
console.log(findStr(testArr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
I have done it... I have used lodash. My code as following:
var arrayData = [];
var teatData = [
{
"Attr": [
{
"power": { "p1": "str", "t3": "str" },
"light": [
{"test": "str"},
{"test2": [ { "t4": "str" }]}
]
}
]
},
{
"Attr1": [
{
"power1": { "p2": "str", "t5": "str" },
"light1": [
{ "test3": "str" },
{ "test_x": [
{ "t_x": "str" },
{ "t_y": [
{ "t_y1": "str" }
]
}
]
}
]
}
]
}
];
function getKeyArray(data, arrayData) {
if (Array.isArray(data)) {
_.forEach(data, (obj, key) => {
this.getKeyArray(obj, arrayData);
});
} else if (_.isPlainObject(data)) {
_.forEach(data, (obj, key) => {
if (obj === "str") {
arrayData.push(key);
} else if (Array.isArray(obj) || _.isPlainObject(obj)) {
this.getKeyArray(obj, arrayData);
}
});
}
}
getKeyArray(teatData, arrayData);
console.log(arrayData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
How to create object using pair values from another object in javascript
Input:
{
firstObject:{
{
"version":"1000",
"issue":"issue1"
},
{
"version":"1001",
"issue":"issue2"
},
{
"version":"1000",
"issue":"issue3"
}
}
}
Above is my input and I want output as following:
{
newObject:{
"1000":["issue1", "issue3"],
"1001":["issue2"]
}
}
Your Input is not a valid JSON. firstObject should be an array instead of object.
Demo
var obj = {
"firstObject": [{
"version": "1000",
"issue": "issue1"
},
{
"version": "1001",
"issue": "issue2"
},
{
"version": "1000",
"issue": "issue3"
}
]
};
var newObject = {};
obj.firstObject.map((item) => {
if( !newObject[ item.version ]){
newObject[item.version] = [];
}
newObject[item.version].push(item.issue);
});
console.log({ newObject });
You can try this
let input = {
firstObject:[
{
"version":"1000",
"issue":"issue1"
},
{
"version":"1001",
"issue":"issue2"
},
{
"version":"1000",
"issue":"issue3"
}
]
}
function createNewObject( input ){
let output= {};
input.firstObject.map(( item ) => {
if( !output[ item.version ]){
output[ item.version ] =[]
}
output[ item.version ].push( item.issue )
})
return({
newObject: output
})
}
console.log( createNewObject( input ))
I have following object records:
{
"notes":[
{
"id":1,
"description":"hey",
"userId":2,
"replyToId":null,
"postId":2,
"parentId":null
},
{
"id":5,
"description":"hey test",
"userId":3,
"replyToId":null,
"postId":2,
"parentId":null
},
{
"id":2,
"description":"how are you",
"userId":null,
"replyToId":2,
"postId":2,
"parentId":null,
"user":null
}
]
}
I want to output it as:
2
object with id 1
object with id 2 (because replyToId value is same as userId
3
object with id 5
So basically I want to consider UserId and replyToId value under the same group.
I have build my own mixin under lodash, wrapping groupBy method as:
mixin({
splitGroupBy: function(list, groupByIter){
if (_.isArray(groupByIter)) {
function groupBy(obj) {
return _.forEach(groupByIter, function (key){
if ( !!obj[key] ) return obj[key]
});
}
} else {
var groupBy = groupByIter;
}
debugger;
var groups = _.groupBy(list, groupBy);
return groups;
}
});
Call looks like this:
_.splitGroupBy(data.notes,['userId', 'replyToId']);
The output is coming without group. Even when I have tried with _.map instead _.forEach the split is not happening correctly.
A solution using underscore:
var props = ['userId', 'replyToId'];
var notNull = _.negate(_.isNull);
var groups = _.groupBy(record.notes, function(note){
return _.find(_.pick(note, props), notNull);
});
This can probably done much prettier, but it should work:
lodash.mixin({
splitGroupBy: function(list, groupByIter) {
var _ = this, groupBy;
if (lodash.isArray(groupByIter)) {
groupBy = function(obj) {
return _(obj) .pick(groupByIter)
.values()
.without(null, undefined)
.first();
};
} else {
groupBy = groupByIter;
}
var groups = _.groupBy(list, groupBy);
return groups;
}
});
You can use stringify object as key.
_.groupBy(notes, ({ userId, replyToId }) => JSON.stringify({ userId, replyToId }));
output:
{
"{\"userId\":2,\"replyToId\":null}": [
{
"id": 1,
"description": "hey",
"userId": 2,
"replyToId": null,
"postId": 2,
"parentId": null
}
],
"{\"userId\":3,\"replyToId\":null}": [
{
"id": 5,
"description": "hey test",
"userId": 3,
"replyToId": null,
"postId": 2,
"parentId": null
}
],
"{\"userId\":null,\"replyToId\":2}": [
{
"id": 2,
"description": "how are you",
"userId": null,
"replyToId": 2,
"postId": 2,
"parentId": null,
"user": null
}
]
}
You could map your list of attributes to their respective values and pick the first non falsy value as your group key:
_.mixin({
splitGroupBy: function(list, groupByIter){
if (!_.isArray(groupByIter))
return _.groupBy(list, groupByIter);
return _.groupBy(list, function(o) {
var values = _.map(groupByIter, function(k) {
return o[k];
});
return _.find(values);
});
}
});
var data = {
"notes":[
{
"id":1,
"userId":2,
"replyToId":null
},
{
"id":5,
"userId":3,
"replyToId":null
},
{
"id":2,
"userId":null,
"replyToId":2
}
]
};
_.mixin({
splitGroupBy: function(list, groupByIter){
if (!_.isArray(groupByIter))
return _.groupBy(list, groupByIter);
return _.groupBy(list, function(o) {
var values = _.map(groupByIter, function(k) {
return o[k];
});
return _.find(values);
});
}
});
snippet.log(JSON.stringify(_.splitGroupBy(data.notes,['userId', 'replyToId'])));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Assuming userId and replyToId are mutually exclusive (i.e. you either have a userId or a replyToId, but never both) as they are in the sample data, then specifying a custom grouping function works:
_.groupBy(data.notes, function(note) {
return note.userId || note.replyToId;
});