0

I am building a CRUD api for a post processing tool. I have some data that have a structure of:

{
  _date: '3/19/2021',
  monitor: 'metric1',
  project: 'bluejays',
  id1: 'test-pmon-2',
  voltageCondition: 'HV',
  testData: [],
  id: null
}

So previous methods I had was I would maintain a separate MongoDB collection which stored high level data of jobs that are stored and these would displayed. This method worked however I would like just one collection for this group of data.

My current method iterates through all objects in the query. The query is relatively small and I set a limit on the return so there is no names really of speed and memory allocation. However, I would like to dev up a more efficient method. This is my current method:

jobHeaderList_2 = [];
queriedData.forEach(doc => {
    if (jobHeaderList_2.length == 0) {
        jobHeaderList_2.push({
            id1: doc.id1,
            project: doc.project,
            monitor: [doc.monitor],
            date: doc._date
        })
    }
    else {
        let index = jobHeaderList_2.map(obj => {
            return obj.id1;
        }).indexOf(doc.id1);

        if (index == -1) {
            jobHeaderList_2.push({
                id1: doc.id1,
                project: doc.projectId,
                monitor: [doc.monitor],
                date: doc._date
            })
        }
        else if (jobHeaderList_2[index].monitor.includes(doc.monitor) == false) {
            jobHeaderList_2[index].monitor.push(doc.monitor);
        }
    }
});

And this works fine, but I would like someone who is more experienced who can maybe help me with a better method of doing this. Basically, I want to group all objects with the same id1 into a single object that stores the monitor values in an array.

I do not want to change the data structure because it's efficient for the plotting that occurs elsewhere in the application.

3
  • How is jobHeaderList_2 initialised? Is it empty when the loop starts? Is queriedData an array, or is it some Mongo query object? Commented Mar 19, 2021 at 19:20
  • queriedData is is an array of objects. jobHeaderList_2 is init as an empty array Commented Mar 19, 2021 at 19:37
  • You received several answers. Could you give feed-back on them, or mark an answer as accepted? Commented Mar 21, 2021 at 9:07

3 Answers 3

1

Here is a solution using vanilla JavaScript, using an ES6 map to key the data by id.

let map = new Map(queriedData.map(doc => [doc.id, {
    id1: doc.id1,
    project: doc.projectId,
    monitor: [],
    date: doc._date
}]));

for (let {id, monitor} of queriedData) map.get(id).monitor.push(monitor);

let jobHeaderList_2 = [...map.values()];
Sign up to request clarification or add additional context in comments.

2 Comments

Hi @trincot. Thanks for the response. I havent seen this method of constructing objects with map. Could you point me to a reference so I can read up on it? Implementing this blindly at the moment.
You can find it in the MDN documentation on the Map() constructor under the Parameters heading. .map (lowercase) returns an array, here in the format that this constructor can deal with. The actual objects are constructed with a simple object literal. So doc.id is the first value of a pair, and the object is the second in that pair. The Map constructor uses those pairs to define the key/values for it.
1

Another option using vanilla Javascript that doesn't require any new knowledge:

const queriedData = [
  {
    _date: '3/19/2021',
    monitor: 'metric1',
    project: 'bluejays',
    id1: 'test-pmon-2',
    voltageCondition: 'HV',
    testData: [],
    id: null,
  },
  {
    _date: '3/20/2021',
    monitor: 'metric2',
    project: 'yellowjays',
    id1: 'test-pmon-2',
    voltageCondition: 'HV',
    testData: [],
    id: null,
  },
  {
    _date: '3/21/2021',
    monitor: 'metric3',
    project: 'orangejays',
    id1: 'test-pmon-3',
    voltageCondition: 'HV',
    testData: [],
    id: null,
  },
]

function accumulateMonitor(queriedData) {
  const jobHeaderList_2 = []
  const indexById = {}

  queriedData.forEach((doc) => {
    const index = indexById[doc.id1]
    if (index === undefined) {
      indexById[doc.id1] = jobHeaderList_2.length
      jobHeaderList_2.push({
        id1: doc.id1,
        project: doc.project,
        monitor: [doc.monitor],
        date: doc._date,
      })
    } else {
      const jobHeader = jobHeaderList_2[index]
      jobHeader.monitor.push(doc.monitor)
    }
  })

  return jobHeaderList_2
}

console.log(accumulateMonitor(queriedData))

/*
[
  {
    id1: 'test-pmon-2',
    project: 'bluejays',
    monitor: [ 'metric1', 'metric2' ],
    date: '3/19/2021'
  },
  {
    id1: 'test-pmon-3',
    project: 'orangejays',
    monitor: [ 'metric3' ],
    date: '3/21/2021'
  }
]
*/

Comments

0

Well I have figured out an answer using pipelining!

I used the $group filter stage, $addToSet and $addFields operator.

const test1 = await pmon.aggregate([
            {
                $group:{
                _id:"$id1",
                monitor:{
                    $addToSet: "$monitor"
                    }
                }
            },
            {
                $addFields:{
                    id1:"$_id"
                }
            }
        ]);

Essentially works as follows:

  • group all elements based on id1
  • add the monitor values using $addToSet
  • finally, added an id1 field back after using this as the value for the _id key.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.