Как я мог бы разделить каждый объект JSON и сгруппировать их в массив в JavaScript?

#javascript #node.js #arrays

#javascript #node.js #массивы

Вопрос:

пример req.files из multer.js

 [
    {
        fieldname: files0,
        originalname: 'Screenshot from 2020-05-23 01-52-30.png',
        encoding: '7bit',
        mimetype: 'image/png',
        destination: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133',
        filename: '1606822252923_Screenshot from 2020-05-23 01-52-30.png',
        path: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133/1606822252923_Screenshot from 2020-05-23 01-52-30.png',
        size: 172092
      },
      {
        fieldname: files0,
        originalname: 'Screenshot from 2020-05-22 08-44-05.png',
        encoding: '7bit',
        mimetype: 'image/png',
        destination: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133',
        filename: '1606822252925_Screenshot from 2020-05-22 08-44-05.png',
        path: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133/1606822252925_Screenshot from 2020-05-22 08-44-05.png',
        size: 440592
      },
      {
        fieldname: files1,
        originalname: 'Screenshot from 2020-05-30 11-36-42.png',
        encoding: '7bit',
        mimetype: 'image/png',
        destination: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133',
        filename: '1606822252930_Screenshot from 2020-05-30 11-36-42.png',
        path: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133/1606822252930_Screenshot from 2020-05-30 11-36-42.png',
        size: 477511
      },
      {
        fieldname: files1,
        originalname: 'Screenshot from 2020-05-30 11-36-36.png',
        encoding: '7bit',
        mimetype: 'image/png',
        destination: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133',
        filename: '1606822252931_Screenshot from 2020-05-30 11-36-36.png',
        path: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133/1606822252931_Screenshot from 2020-05-30 11-36-36.png',
        size: 223362
      },
      {
        fieldname: files1,
        originalname: 'Screenshot from 2020-05-30 11-36-31.png',
        encoding: '7bit',
        mimetype: 'image/png',
        destination: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133',
        filename: '1606822252932_Screenshot from 2020-05-30 11-36-31.png',
        path: 'public/uploads/projects/0a480789-eb14-4fe4-bb89-44aa741efe33/proposals/chma00000133/1606822252932_Screenshot from 2020-05-30 11-36-31.png',
        size: 260419
      }
]
 

Я хочу динамически группировать каждый объект JSON с их именем поля и сохранять их в массиве объектов, используя их номер имени поля в качестве индекса массива.

Группы могут быть от 0 до 9, в зависимости от пользовательского ввода.

Результат, на который я надеюсь, это что-то вроде

 someArr = [

    [
        {
            fieldname: files0
            originalname: somevalue,
            ...
            size: some value
        },
        {
            fieldname: files0,
            originalname: somevalue,
            ...
            size: some value
        },
    ]
        ,
    [
        
        {
            fieldname: files1,
            originalname: somevalue,
            ...
            size: some value
        },
        {
            fieldname: files1,
            originalname: somevalue,
            ...
            size: some value
        },
        {
            fieldname: files1,
            originalname: somevalue,
            ...
            size: some value
        },
    ]
    ...
    
]
 

и если он существует, someArr[9] вернет

 [

    {
        fieldname: files9,
        originalname: somevalue,
        ...
        size: some value
    },
    {
        fieldname: files9,
        originalname: somevalue,
        ...
        size: some value
    },
]
 

То, что я попробовал, — это сначала проанализировать целые числа из имен полей и переназначить их как свои значения для лучшей сортировки с помощью for-циклов

 Object.keys(req.files).forEach((key) => {
  const thisFile = req.files[key];
  const thisFileGroup = parseInt(thisFile.fieldname.match(/d/g).join(''), 10); 
  // rename fieldname from files0, files1 ... to 0 , 1 ....
  req.files[key].fieldname = thisFileGroup;
});
 

Но отсюда я не могу найти, куда поместить этот элемент (thisFile), поскольку я не могу предварительно указать каждый массив в верхней области видимости, поскольку они также должны создаваться динамически.

Комментарии:

1. Пожалуйста, примите ответ @mplungjan. Я пропустил, что вам нужно упорядочивать по индексу 0 и 1 т. Д. Использование object отлично подходит для группировки, но окончательный порядок не будет упорядочен по алфавитному порядку ключей.

2. @Roko C. Buljan проверено! Я обязательно также буду иметь в виду ваше решение!

Ответ №1:

Я бы использовал сокращение

 const data = [ 
{ fieldname: 'files0', originalname: 'Screenshot from 2020-05-23 01-52-30.png', },
{ fieldname: 'files0', originalname: 'Screenshot from 2020-05-22 08-44-05.png', },
{ fieldname: 'files1', originalname: 'Screenshot from 2020-05-30 11-36-42.png', },
{ fieldname: 'files1', originalname: 'Screenshot from 2020-05-30 11-36-36.png', },
{ fieldname: 'files1', originalname: 'Screenshot from 2020-05-30 11-36-31.png', }],
arr = data.reduce((acc, cur) => {
  const idx = cur.fieldname.replace("files",""); // get 0, 1
  if (acc[idx]) acc[idx].push(cur); // if already there, just push
  else acc[idx] = [cur];            // otherwise initialise
  return acc;
},[]) 

console.log(arr) 

ПРИМЕЧАНИЕ: группы могут быть от 0 до 9, в зависимости от пользовательского ввода.

Я предполагаю, что дыр нет, поскольку это может привести к разреженному массиву, поэтому

 data = [ 
     { fieldname : 'files0' },
     { fieldname : 'files0' },
     { fieldname : 'files3' },
     { fieldname : 'files3' },
 }
 

создало бы массив

 [
  [ { fieldname : 'files0' }, { fieldname : 'files0' } ],
  null,
  null,
  [ { fieldname : 'files3' }, { fieldname : 'files3' } ],
]
 

Комментарии:

1. чисто и просто!! отличный ответ!! Я должен искать reduce

2. @mplungjan да, понял! Нет fieldname replace -ing! да! : P 😉

3. Единственная проблема, которую я вижу в своем коде, — это null, если есть filesx или files0,1,3

4. @viviet Я думаю, что это тот ответ, который вам нужен, используя объекты (как я и предлагал), вы потеряете порядок индексов групп!

5. @mplungjan извиняюсь, я полностью пропустил в вопросе OP «порядок по индексу» . 1

Ответ №2:

Если вам не нужен обязательно порядок по индексу files[index]

в этом случае вы могли бы преобразовать Array.prototype.reduce() в Object.
Ваш объект будет сгруппирован по fieldname свойствам (хотя и не в алфавитном порядке), содержащим один массив с элементами, имеющими тот же ключ свойства.
Выполните итерацию вашего объекта, используя Object.values()Array.prototype.forEach(), если это необходимо).

 const data = [
  { fieldname: "files0", originalname: '0-a'},
  { fieldname: "files0", originalname: '0-b'},
  { fieldname: "files1", originalname: '1-a'},
  { fieldname: "files1", originalname: '1-b'},
  { fieldname: "files1", originalname: '1-c'},
];

const byFieldName = data.reduce((ob, d) => {
  if (!ob.hasOwnProperty(d.fieldname)) ob[d.fieldname] = [];
  ob[d.fieldname].push(d);
  return ob;
}, {});

// console.log(byFieldName); // Uncomment to see how it looks like
console.log( Object.values(byFieldName) ); 

Комментарии:

1. Этот код сначала уменьшает, а затем принимает значения объекта, чтобы избавиться от ключа byFieldName — это неэффективно — это безопаснее, чем полагаться на цифру в ключе, но если это гарантировано, то мой код более эффективен

2. Это упорядочит конечный массив по порядку, в котором значения fieldname встречаются во входном массиве. Вам нужно будет отсортировать исходный массив по имени поля, прежде чем сокращать его с помощью этого подхода.

3. Объект или массив — это данные. Вы @mplungjan можете игнорировать второй журнал консоли и рассматривать этот ответ так, как если бы первый был раскомментирован. Вы все равно будете зацикливать данные, если вам нужно получить значения. Лучшая часть в том, чтобы иметь его в качестве структурированного объекта, заключается в том, что вы можете — при необходимости — напрямую использовать весь массив, используя его ключ: const fn1 = byFieldName["files0"] при использовании массива вам необходимо получить доступ к глубоким слоям и выполнить их итерацию, чтобы каждый .some() из элементов соответствовал желаемому ключу.

4. Порядок свойств объектов @pilchard предсказуем в JavaScript ES2015 — после этого цикл не имеет разницы в вводе.

5. пилчард да, я знаю, но в этом предложении нет необходимости (то есть просто группировать их и пользоваться преимуществами — жестко, а не в алфавитном порядке ) дополнительные итерации могут быть слишком дорогими для чего-то, что @mplungjan уже решил. — И PS, я пропустил в вопросе необходимость упорядочивания OP по индексу .

Ответ №3:

Я стараюсь не изменять вашу логику, чтобы сделать это.
если нет files2 , то filesArray[2] будет undefined .

 // Omit other fields
const req = {
    files: [
        { fieldname: "files0", originalname: 'Screenshot from 2020-05-23 01-52-30.png'},
        { fieldname: "files0", originalname: 'Screenshot from 2020-05-22 08-44-05.png'},
        { fieldname: "files1", originalname: 'Screenshot from 2020-05-30 11-36-42.png'},
        { fieldname: "files1", originalname: 'Screenshot from 2020-05-30 11-36-36.png'},
        { fieldname: "files1", originalname: 'Screenshot from 2020-05-30 11-36-31.png'},
        { fieldname: "files3", originalname: 'Screenshot from 2020-05-30 11-36-42.png'},
        { fieldname: "files3", originalname: 'Screenshot from 2020-05-30 11-36-36.png'},
        { fieldname: "files3", originalname: 'Screenshot from 2020-05-30 11-36-31.png'}
    ]
}

let filesArray = []

for (let file of req.files) {
    const thisFileGroup = parseInt(file.fieldname.match(/d/g).join(''), 10);
    if (!filesArray[thisFileGroup]) {
        filesArray[thisFileGroup] = []
    }
    filesArray[thisFileGroup].push(file)
}

console.log(filesArray[2]) // will be undefined
console.log(filesArray[1]) // will be files1 array
console.log(filesArray)