如何在我的特定情况下形成一个嵌套数组的数组?

4
我有一个特定的用例,我想将数组中的所有对象合并成一个新数组。所以我在我的网站上有一个表单,用户在预订时添加参与者。他们可以添加任意数量的参与者。我将它们保存为JSON格式并存储在数据库中,现在我想形成所有参与者的数组,以便可以在表格中显示它们。
因此,我首先从特定列表中获取所有交易,得到一个对象数组,然后循环遍历它们,并且仅获取transaction.attributes.protectedData.questions,这个属性包含每个交易的参与者。
因此,我的transactions对象看起来像:
[
   {
      "type":"transaction",
      "attributes":{
         "createdAt":"2021-06-24T08:50:26.911Z",
         "protectedData":{
            "questions":[
               [
                  {
                     "question":"name",
                     "answer":"Mario North"
                  },
                  {
                     "question":"email",
                     "answer":"mario@gmail.com"
                  }
               ]
            ],
            "ticketType":{
               "name":"Main entry",
               "quantity":1
            }
         }
      }
   },
   {
      "type":"transaction",
      "attributes":{
         "createdAt":"2021-06-24T08:48:57.646Z",
         "protectedData":{
            "questions":[
               [
                  {
                     "question":"name",
                     "answer":"John Adkins"
                  },
                  {
                     "question":"email",
                     "answer":"john@gmail.com"
                  }
               ],
               [
                  {
                     "question":"name",
                     "answer":"Thomas Smith"
                  },
                  {
                     "question":"email",
                     "answer":"thomas@gmail.com"
                  }
               ]
            ],
            "ticketType":{
               "name":"General entry",
               "quantity":2
            }
         }
      }
   }
]

所以我需要遍历每个交易,然后循环遍历问题和问题数组中的每个新数组是一个新的参与者。在每个参与者中,我需要从交易属性保存createdAt和ticketType值。

所以我的最终数组/对象应该像这样:

[
   {
      "createdAt":"2021-06-24T08:50:26.911Z",
      "ticketType":"Main entry",
      "name":"Mario North",
      "email":"mario@gmail.com"
   },
   {
      "createdAt":"2021-06-24T08:48:57.646Z",
      "ticketType":"General entry",
      "name":"John Adkins",
      "email":"john@gmail.com"
   },
   {
      "createdAt":"2021-06-24T08:48:57.646Z",
      "ticketType":"General entry",
      "name":"Thomas Smith",
      "email":"thomas@gmail.com"
   }
]

我可以获取参与者列表,并为每个参与者添加createdAt和ticketType。但我不知道如何使我的问题/答案出现在我所发布的期望对象中。这是我的代码:

export const denormalisedParticipantList = transactions => {
  let participants = [];

  transactions.map(transaction => {
    const createdAt = transaction.attributes.createdAt;
    const questions = transaction.attributes.protectedData?.questions;
    const ticketType = transaction.attributes.protectedData?.ticketType?.name;

    return questions.map(q => {
      // Form new participant object
      const participant = {
        createdAt,
        ticketType,
        ...Object.fromEntries(q.map(({ question, answer }) => [question, answer])),
      };

      // Push new participant
      participants.push(participant);
    });
  });

  return participants;
};

自从昨晚开始我一直在尝试弄清楚它,但我无法使它工作。请问有人能帮助我弄清楚如何从我的交易对象中制作最终数组吗?我会非常感激。


展示你的尝试,这样我们就可以看到你如何尝试解决它。 - Emiel Zuurbier
我会将其发布在我的问题底部。谢谢! - Miodrag Sumaric
3个回答

2
“解构”( Destructuring)是一种强大的方式,可以帮助你追踪访问复杂对象时的情况。在这里,使用 flatMap() 来返回一个单独的扁平化数组,并使用 Object.fromEntries()questions 数组映射到各个对象中。”

const input = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario@gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john@gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas@gmail.com" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]

const result = input.flatMap((
  {
    attributes: {
      createdAt,
      protectedData: {
        questions,
        ticketType: { name: ticketType } }
    }
  }
) => (
  questions.map(p => ({
    createdAt,
    ticketType,
    ...Object.fromEntries(p.map(({ question, answer }) => [question, answer]))
  }))
));

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }


嘿,pilchard,你的解决方案完美地运行,并且非常干净。非常感谢。你能解释一下使用flatMap与我在问题中发布的方式有什么区别吗?我刚刚编辑了它。我也应该使用flatMap吗? - Miodrag Sumaric
你的代码中使用了 map(),但没有利用返回的数组。这是低效的,但也是你没有得到嵌套数组的原因,因为你手动将每个嵌套对象推送到结果数组中。你应该用 forEach() 替换你的 map() 调用或者利用 map 的返回值。 - pilchard
感谢您的评论,pilchard。我已将您的答案标记为已接受。 - Miodrag Sumaric
没问题,很高兴能帮到你。 - pilchard

1
var array = []
data.forEach((element) => {
var object = { created: null,ticketType: null,name: null,email: null }
object.created = element.attributes.createdAt;
object.ticketType = element.attributes.protectedData.ticketType.name;
var tmp_data = element.attributes.protectedData.questions;
tmp_data.forEach((tmp) => {
    tmp.forEach((item) => {
        if(item.question == "name"){
            object.name = item.answer;
        }else{
            object.email = item.answer;
        }
    })
    array.push(object);
})
})

尝试这个 :)

非常感谢你的回答,米歇尔!它也帮了我很多。看起来非常简洁。如果我在我的React项目中使用这种JavaScript类型的答案,可以吗? - Miodrag Sumaric

1
你可以简单地使用reducemap

const data = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario@gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john@gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas@gmail.com" },{ "question": "gender", "answer": "male" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]


const output = data.reduce(
  (a, b) => [
    ...a,
    ...b.attributes.protectedData.questions.map(e => ({
      createdAt: b.attributes.createdAt,
      ticketType: b.attributes.protectedData.ticketType.name,
      ...e.reduce((acc, cur) => ({ ...acc, [cur.question]: cur.answer }), {}),
    })),
  ],
  []
);

console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }


非常感谢,这看起来非常干净。但是如果我有更多问题该怎么办(因为有时候姓名和电子邮件不是唯一的问题)。是否有一种动态生成它们的方法? - Miodrag Sumaric
@MiodragSumaric,可以的。我更新了我的回答。您可以看到最后一项包含一个性别问题。 - ikhvjs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接