从深层嵌套的数组对象结构中提取值

huangapple go评论61阅读模式
英文:

Javascript extracting values from deeply nested array object structure

问题

我尝试从后端数据中提取特定字段,以准备表格的主体。输入的数据结构如下:

[
  {
    "_id": "63056cee252b83f4bc8f97e9",
    "goals": [
      { "title": "Cook" },
      { "title": "Budget" }
    ],
    "visitEnd": "2022-08-18T00:30:00.000Z",
    "visitStart": "2022-08-17T21:30:00.000Z"
  },
  {
    "_id": "63223586798c6b2658a0d576",
    "goals": [
      { "title": "Cook" },
      { "title": "Budget" },
      { "title": "Clean" }
    ],
    "visitEnd": "2022-09-13T00:30:00.000Z",
    "visitStart": "2022-09-12T22:00:00.000Z"
  },
  {
    "_id": "63542ecfca5bd097a0d9acaf",
    "goals": [
      { "title": "Cook" },
      { "title": "Clean" }
    ],
    "visitEnd": "2022-10-12T19:00:11.000Z",
    "visitStart": "2022-10-12T17:00:00.000Z"
  }
]

由于表格标题是按月/年分组的,我使用 lodash 按月分组,得到以下结果:

{
  "7": [
    { "user": "62410a1dcaac9a3d0528de7a", "location": "Firm Office in LA", "visitStart": "2022-08-17T21:30:00.000Z", ... },
    { "user": "62410a1dcaac9a3d0528de7a", "location": "place", "visitStart": "2022-08-11T21:00:57.000Z", ... }
  ],
  "8": [
    { "user": "62410a1dcaac9a3d0528de7a", "location": "Home", "visitStart": "2022-09-12T22:00:00.000Z", ... },
    { "user": "62410a1dcaac9a3d0528de7a", "location": "place", "visitStart": "2022-09-21T21:00:00.000Z", ... }
  ],
  "9": [
    { "user": "62410a1dcaac9a3d0528de7a", "location": "Home", "visitStart": "2022-10-12T17:00:00.000Z", ... },
    { "user": "62410a1dcaac9a3d0528de7a", "location": "place", "visitStart": "2022-10-21T21:00:00.000Z", ... }
  ]
}

但是现在我陷入困境,因为我想隔离每个月的数组中的对象中的 goals 数组字段。我尝试使用 Object.keys 和 map 进行操作,然后在这里:https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4,找到了一个获取深层嵌套项的函数。但我仍然搞砸了,我头晕目眩,试图弄清楚这一切。我看了 lodash 的 map 和 property,但不确定如何在动态命名的数组中实现,这些数组位于 groupBy 对象内的嵌套层次中。这是我的尝试,但我得到了错误,提示 i.map 不是一个函数:

const sort = groupBy(visits, ({visitEnd}) => new Date(visitEnd).getMonth());
console.log("sort 1: ", sort)
const stage = Object.keys(sort).map((i) => {
   { i.map((el) => getNestedObject(el, ['goals', 'title'])) }
})
console.log("sort 2: ", stage)
英文:

I'm trying to pull out specific fields from backend data to prep the body of a table. The data coming in has the structure of:

[
{
_id: "63056cee252b83f4bc8f97e9",
goals: [
{ title: "Cook" },
{ title: "Budget" }
],
visitEnd: "2022-08-18T00:30:00.000Z",
visitStart: "2022-08-17T21:30:00.000Z",
},
{
_id: "63223586798c6b2658a0d576",
goals: [
{ title: "Cook" },
{ title: "Budget" },
{ title: "Clean" }
],
visitEnd: "2022-09-13T00:30:00.000Z",
visitStart: "2022-09-12T22:00:00.000Z"
},
{
_id: "63542ecfca5bd097a0d9acaf",
goals: [
{ title: "Cook" },
{ title: "Clean" }
],
visitEnd: "2022-10-12T19:00:11.000Z",
visitStart: "2022-10-12T17:00:00.000Z",
}]

Since the table headers are by month/year, I'm using lodash to group them by month, which gets me here:

Object { 7: (2) […], 8: (2) […], 9: (2) […] }
​
7: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Firm Office in LA", visitStart: "2022-08-17T21:30:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-08-11T21:00:57.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
8: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-09-12T22:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-09-21T21:00:00.000Z", … }
​​
length: 2
​​
<prototype>: Array []
​
9: Array [ {…}, {…} ]
​​
0: Object { user: "62410a1dcaac9a3d0528de7a", location: "Home", visitStart: "2022-10-12T17:00:00.000Z", … }
​​
1: Object { user: "62410a1dcaac9a3d0528de7a", location: "place", visitStart: "2022-10-21T21:00:00.000Z", … }
​​
length: 2

But now I'm stuck since I want to isolate the fields of the goals array, which is within the objects, within the array of each month, which is contained in an object. I've tried playing around with Object.keys and maps, and then from here: https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4 came across a function to get deeply nested items. But I'm still messing this up, and my head is spinning trying to make sense of it. I looked at lodash's map and property, but was not sure how to implement given the layers of nesting I'm trying to work through on dynamically named arrays within the groupBy object. Heres where I'm at, but I'm getting the error i.map is not a function

const sort = groupBy(visits, ({visitEnd})=> new Date(visitEnd).getMonth());
   console.log("sort 1: ", sort)
   const stage = Object.keys(sort).map((i) => {
      { i.map((el) => getNestedObject(el, ['goals', 'title'])) }
      })
   console.log("sort 2: ", stage)

My javascript knowledge is terrible which doesn't help...

答案1

得分: 1

你得到的错误,i.map 不是一个函数,意味着变量 i 不是一个数组。根据你在帖子中提供的数据,i 是一个对象。

使用 Object.entries() 而不是 Object.keys() 迭代按月/年排序的结果数据。

要获取每月独特目标的列表,输出如下所示:

{
    7: ["Cook", "Spend", "Clean"],
    8: ["Cook", "Budget", "Clean"],
    9: ["Cook", "Budget", "Scrub", "Fold", "Rest", "Wash"]
}
英文:

The error you're getting, i.map is not a function, means that the variable i is not an array. Based on the data you supplied in your post i is an object.

Iterate the result of the sorted month/year data using Object.entries() versus Object.keys().

To get a list of unique goals per month with output that looks like:

{
    7: ["Cook", "Spend", "Clean"],
    8: ["Cook", "Budget", "Clean"],
    9: ["Cook", "Budget", "Scrub", "Fold", "Rest", "Wash"]
}

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const dataSortedByMoYrObj = {
  7: [{
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;Firm Office in LA&quot;,
      visitStart: &quot;2022-08-17T21:30:00.000Z&quot;,
      goals: [{
          title: &quot;&quot;
        },
        {
          title: &quot;Spend&quot;
        },
        {
          title: &quot;Clean&quot;
        }
      ]
    },
    {
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;place&quot;,
      visitStart: &quot;2022-08-11T21:00:57.000Z&quot;,
      goals: [{
          title: &quot;Cook&quot;
        },
        {
          title: undefined
        }
      ]
    }
  ],
  8: [{
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;Home&quot;,
      visitStart: &quot;2022-09-12T22:00:00.000Z&quot;,
      goals: [{
          title: &quot;Cook&quot;
        },
        {
          title: &quot;Budget&quot;
        },
        {
          title: null
        }
      ]
    },
    {
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;place&quot;,
      visitStart: &quot;2022-09-21T21:00:00.000Z&quot;
    }
  ],
  9: [{
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;Home&quot;,
      visitStart: &quot;2022-10-12T17:00:00.000Z&quot;,
      goals: [{
          title: &quot;Cook&quot;
        },
        {
          title: &quot;Budget&quot;
        },
        {
          title: &quot;Scrub&quot;
        }
      ]
    },
    {
      user: &quot;62410a1dcaac9a3d0528de7a&quot;,
      location: &quot;place&quot;,
      visitStart: &quot;2022-10-21T21:00:00.000Z&quot;,
      goals: [{
          title: &quot;Fold&quot;
        },
        {
          title: &quot;Rest&quot;
        },
        {
          title: &quot;Wash&quot;
        }
      ]
    }
  ]
};

// &#39;const getNestedObject&#39; code sourced from:
// https://dev.to/flexdinesh/accessing-nested-objects-in-javascript--9m4
const getNestedObject = (nestedObj, pathArr) =&gt; {
  return pathArr.reduce((obj, key) =&gt;
    (obj &amp;&amp; obj[key] !== &#39;undefined&#39;) ? obj[key] : undefined, nestedObj);
}

const goalsByMonthYearObj = {};
Object.entries(dataSortedByMoYrObj).forEach(([month, users]) =&gt; {
  // &#39;month&#39; represents the key.
  // &#39;users&#39; is an array of &#39;user&#39; objects listed for each month.
  let goalsByMonth = [];
  users.forEach(user =&gt; {
    const goalsProp = getNestedObject(user, [&#39;goals&#39;]);
    // Check if the &#39;goals&#39; property is a valid.
    // If &#39;goals&#39; property is &#39;null&#39; or &#39;undefined&#39;,
    // &#39;!Array.isArray(null)&#39; returns &#39;true&#39;.
    if (!Array.isArray(goalsProp)) {
      return;
    }
    // Convert list of goal objects (e.g. &#39;{title: Budget}&#39;)
    // to an array using &#39;goalsProp.map()&#39;.
    // Use the &#39;filter()&#39; method first to remove empty strings
    // &#39;null&#39; and &#39;undefined&#39; values in the &#39;title&#39; property.
    // https://stackoverflow.com/questions/24806772/how-to-skip-over-an-element-in-map
    const goalsArr = goalsProp.filter(goal =&gt; goal.title).map(goal =&gt; goal.title);
    // Concatenate goals array to the existing goals-by-month array.
    goalsByMonth = goalsByMonth.concat(goalsArr);
  });
  // Sort array of goals alphabetically
  // https://stackoverflow.com/a/45544166
  goalsByMonth.sort((a, b) =&gt; a.localeCompare(b));
  // Add array of unique goals for each month
  // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
  goalsByMonthYearObj[month] = [...new Set(goalsByMonth)];
});
console.log(goalsByMonthYearObj);

<!-- end snippet -->

(Original code that's not as concise as above snippet.)

const goalsByMonthYearObj = {};

// Reference to &#39;Object.entries()&#39; at:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
for (const [key, value] of Object.entries(dataSortedByMoYrObj)) {
    // &#39;key&#39; represents a month index.
    // &#39;value&#39; contains an array of objects listed for each month index.
    //console.log(`${key}: ${value}`);

    const goalsByMonth = [];

    value.forEach(item =&gt; {
        // The &#39;goals&#39; property is only one level deep so
        // it&#39;s not necessary to use the &#39;getNestedObject()&#39;
        // function. 
        // For example: const goalsProp = item.goals;
        // The function is useful for more deeply
        // embedded properties. 
        const goalsProp = getNestedObject(item, [&#39;goals&#39;]);

        if (!Array.isArray(goalsProp)) { return; }

        goalsProp.forEach(goal =&gt; {
            if (!goal.title) { return; }
            goalsByMonth.push(goal.title);
        });
    });

    // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
    const uniqueGoals = [...new Set(goalsByMonth)];

    goalsByMonthYearObj[key] = uniqueGoals;
}

console.log(goalsByMonthYearObj);

huangapple
  • 本文由 发表于 2023年2月18日 07:17:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490045.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定