根据程序名称组合两个数据集

Combining two data sets based on programme name

您好,我正在努力找出实现目标的最佳方法。我实际上是在进行两次数据库调用

const [emails] = await dbConnection.execute('SELECT name, programme, timestamp FROM emails');
const [emailsCancelled] = await dbConnection.execute('SELECT data FROM emails where name = "email.cancelled"');

我进行两次调用的原因是我正在处理超过十万行,并且数据字段包含相当多的 JSON 数据,所以不想为所有行检索它.

因此,对于电子邮件,我以以下格式取回数据

[
    {
    name: 'email.sent',
    programme: 'Email One',
    timestamp: 2022-03-24T18:06:02.000Z
    },
    {
    name: 'email.sent',
    programme: 'Email Two',
    timestamp: 2022-03-24T18:06:02.000Z
    },
    {
    name: 'email.sent',
    programme: 'Email One',
    timestamp: 2022-03-24T18:06:02.000Z
    },
    ...
]

所以我需要做的是按节目分组,以确定发送了多少和总计数。我确实获得了一些其他细节,但为此减少了 post。为此,我这样做

const emailsReduced = await emails.reduce((acc, o) => {
  const name = o.name?.replace('email.', '');
  if (!acc[o.programme]) {
    acc[o.programme] = {
      count: 0,
      sent: 0,
    };
  }
  acc[o.programme].count = (acc[o.programme].count || 0) + 1;
  acc[o.programme][name] = (acc[o.programme][name]) + 1;

  return acc;
}, {});

那会 return 像这样

'Email One': {
    count: 2,
    sent: 2,
},
'Email Two': {
    count: 1,
    sent: 1,
},

现在电子邮件已取消 returns JSON 数据。所以我能做的就是循环它并显示我需要的部分的示例

Object.entries(emailsCancelled).forEach(([key, value]) => {
  const data = JSON.parse(value.data);
  if (data?.payload?.body?.toUpperCase() === 'STOP') {
    console.log(data?.payload?.correlation?.metadata);
  }
});

这将产生这样的行

[
    { customerId: '12345', programName: 'Email One' },
    { customerId: '2321', programName: 'Email Two' },
    { customerId: '33321', programName: 'Email Two' }
]

现在我需要做的是将其作为计数放入原始数组。因此,您可以看到电子邮件一取消了 1 个,邮件二取消了 2 个。所以我需要像这样添加它,根据程序名称匹配它。

'Email One': {
    count: 2,
    sent: 2,
    cancelled: 1,
},
'Email Two': {
    count: 1,
    sent: 1,
    cancelled: 2,
},

我怎样才能实现这样的目标?

谢谢

实际格式

{
   "name":"email.cancelled",
   "payload":{
      "body":"STOP",
      "correlation":{
         "metadata":{
            "customerId":"232131232113",
            "programName":"Email One"
         }
      },
      "id":"123454323343232",
      "receivedOn":"2022-05-15T12:51:54.403Z"
   },
}

假设您的数据结构如下所示,您可以根据 emails 键进行映射和过滤:

const emails = [
    { 'Email One': {
    count: 2,
    sent: 2,
    }},
    {'Email Two': {
    count: 1,
    sent: 1,
    }}
]

const canceled = [
  { customerId: '12345', programName: 'Email One' },
  { customerId: '2321', programName: 'Email Two' },
  { customerId: '33321', programName: 'Email Two' }
]

const newmails = emails.map(mail => {
  let strmail = Object.keys(mail)
  let ncanceled = canceled.filter(item => {
    return item.programName == strmail
  }).length
  mail[strmail].canceled = ncanceled
  return mail
})

console.log(newmails)

emailsCancelled 开始,您可以在 emails 上执行 .reduce() 之前将数组缩减为查找 Map。查找会将 programName 存储为键,并将该程序的计数存储为值:

const emails = [
    { customerId: '12345', programName: 'Email One' },
    { customerId: '2321', programName: 'Email Two' },
    { customerId: '33321', programName: 'Email Two' }
];

const lut = emails.reduce((map, {programName}) => 
  map.set(programName, (map.get(programName) || 0) + 1)
, new Map);

console.log(lut.get("Email One"));
console.log(lut.get("Email Two"));

您也可以直接从 .forEach() 循环构建此地图,请注意我使用的是 Object.values() 而不是 .entries() 因为您只对值感兴趣而不是钥匙:

const lut = new Map();
Object.values(emailsCancelled).forEach(value => {
  const data = JSON.parse(value.data);
  if (data?.payload?.body?.toUpperCase() === 'STOP') {
    const programName = data.payload.correlation?.metadata?.programName; // if `correcltation`, or `metadata` or `programName` don't exist, use optional chaining and an if-statement to check for `undefined` before updating the map.
    lut.set(programName, (map.get(programName) || 0) + 1)
  }
});

当您在电子邮件上使用 .reduce() 时,您可以使用此查找 lut 映射来计算 cancelled 值,默认 cancelled0如果在地图中找不到程序:

const emailsReduced = await emails.reduce((acc, o) => {
  const name = o.name?.replace('email.', '');
  if (!acc[o.programme]) {
    acc[o.programme] = {
      count: 0,
      sent: 0,
      cancelled: lut.get(o.programme) || 0 // default to zero if program can't be found
    };
  }
  acc[o.programme].count = acc[o.programme].count + 1;
  acc[o.programme][name] = acc[o.programme][name] + 1;

  return acc;
}, {});

试试这个!

const emails = [{
    'Email One': {
      count: 2,
      sent: 2,
      cancelled: 0,
    },
  },
  {
    'Email Two': {
      count: 1,
      sent: 1,
      cancelled: 0,
    },
  },
];

const cancelled_emails = [{
    customerId: '12345',
    programName: 'Email One'
  },
  {
    customerId: '2321',
    programName: 'Email Two'
  },
  {
    customerId: '33321',
    programName: 'Email Two'
  },
];



for (let cancelled_email of cancelled_emails) {
  let prg_name = cancelled_email.programName;

  for (email of emails) {

    if (Object.keys(email)[0] === prg_name) {
      email[prg_name].cancelled += 1;
    }
  }
}

console.log(emails);