Get all array elements in one array mongodb + node.js - javascript

Let's assume I've collection which has the following structure;
{
id:1,
name: 'name1',
students: ['1', '2' , '3']
}
{
id:2,
name: 'name2',
students: ['11', '22' , '33']
}
...
I want to get all students element in one array.
I can do as:
db.collection.find({}, {students: 1, _id:0})
This returns me an array as;
result = [
{students: ['1', '2', '3']},
{students: ['11', '22','33']},
]
However I want to get result = ['1', '2', '3', '11', '22','33'];
What is the most efficient way to get result just like this?

If you want to go JavaScript way, Use Array.prototype.reduce
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
Try this:
var result = [{
students: ['1', '2', '3']
}, {
students: ['11', '22', '33']
}, ];
var merged = result.reduce(function(a, b) {
return a.students.concat(b.students);
});
console.log(merged);

You can use the aggragation framework:
db.collection.aggregate([{
$unwind: '$students'
},{
$group: {
_id: '1',
students: {
$push: '$students'
}
}
}])

Try with aggregation framework.
db.collection.aggregate([
{$project:{_id:0, students:1}},
{$group:{_id:null, result:{$push:"$$ROOT"}}},
{$project:{_id:0, result:1}}
])
This will emit:
{
"result" : [
{
"students" : [
"1",
"2",
"3"
]
},
{
"students" : [
"11",
"22",
"33"
]
}
]
}

Related

Convert a javascript array of multiple similar objects into a smaller array with repeated values as a sub array

I have an array like this where employeeIds can show up multiple times with different codes.
employees: [
{
employeeId: '2',
code: 64897
},
{
employeeId: '4'
code: 64897
},
{
employeeId: '1',
code: 64897
},
{
employeeId: '4',
code: 67986
},
{
employeeId: '1',
code: 67986
}]
What is the best way to turn this into an array where employeeIds show up once but have an array of all their codes from the initial data like this?
employees: [
{
employeeId: '2',
codes: [64897]
},
{
employeeId: '1',
codes: [64897, 67986]
},
{
employeeId: '4',
codes: [64897, 67986]
}]
Reduced the employees array into a Map where the key of the Map is the employeeId and the value is an array of employee codes.
Created an array out that Map using Array.from().
Check the code snippet below:
const employees = [
{ employeeId: '2', code: 64897 },
{ employeeId: '4', code: 64897 },
{ employeeId: '1', code: 64897 },
{ employeeId: '4', code: 67986 },
{ employeeId: '1', code: 67986 },
];
const merged = Array.from(
employees.reduce(
(res, { employeeId, code }) => (
res.has(employeeId)
? res.get(employeeId).push(code)
: res.set(employeeId, [code]),
res
),
new Map()
),
([employeeId, code]) => ({ employeeId, code })
);
console.log(merged);
This sounds like a good place to use reduce(). Essentially, we can loop through the array of objects and reduce it to an array of the consolidated employee objects. This should work:
let employees = [
{
employeeId: '2',
code: 64897
}, {
employeeId: '4',
code: 64897
}, {
employeeId: '1',
code: 64897
}, {
employeeId: '4',
code: 67986
}, {
employeeId: '1',
code: 67986
}
];
employees = employees.reduce((a,c) => (a.find(e => e.employeeId === c.employeeId) ? a.find(e => e.employeeId === c.employeeId).codes.push(c.code) : a.push({ employeeId: c.employeeId, codes: [c.code] }), a), []);
console.log(employees);
More information on reduce here (MDN docs). It's still the one array prototype function I'm struggling to master, but it's very powerful.
You could reduce with a Map and create new object from the entries of the map.
const
employees = [{ employeeId: '2', code: 64897 }, { employeeId: '4', code: 64897 }, { employeeId: '1', code: 64897 }, { employeeId: '4', code: 67986 }, { employeeId: '1', code: 67986 }],
grouped = Array.from(
employees.reduce((m, { employeeId, code }) =>
m.set(employeeId, [...(m.get(employeeId) || []), code]), new Map),
([employeeId, code]) => ({ employeeId, code })
);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Create an array of object from given array key

I have array like this .
const test = [
{ student: { id : '1', Name: 'A' }, marks: {
 id: '2', Name: 'B'
} },
{ student: {
 id : '3', Name: 'C' }, marks: { id: '4', Name: 'D' } }
]
Now, from this array of object , I am trying to create two diff arrays which will be having seperate student and marks keys .
const student = [{"student":{"Id": {value: "A"}}}, {"student":{"Id": {value: "B"}}}]
and for marks
const marks = [{"marks":{"Id": {value: "C"}}}, {"marks":{"Id": {value: "D"}}}]
SO, Here what I tried is
test.map((index,item) => {
return [item.student]
})
can any one help me with this ?
Thanks.
You want a new object returned, not a sub array.
Following uses destructuring to simplify the returned object
const test = [
{ student: { id : '1', Name: 'A' }, marks: {
id: '2', Name: 'B'
} },
{ student: {
id : '3', Name: 'C' }, marks: { id: '4', Name: 'D' } }
]
const students = test.map(({student}) => ({student}))
const marks = test.map(({marks}) => ({marks}))
console.log(students)
console.log(marks)

Javascript multilevel object spread operator

I have an array of objects, I want all data out from all objects into multiple arrays
const obj = [
{
school: {
name: 'abc',
students: [
{
class: 'A',
name: 'jhon',
},
{
class: 'B',
name: 'Doe',
},
],
},
},
{
school: {
name: 'XYZ',
students: [
{
class: 'C',
name: 'Cena',
},
{
class: 'B',
name: 'Big show',
},
],
},
},
];
I want result something like
[ ["abc", "xyz"], ["A", "B", "C", "B"], ["jhon", "Doe", "Cena", "Big show"]]
Any help will be appreciated
You can make use of reduce and take Object.values of it. While traversing the student array you can take Object.entries of Object. Here is a working example:
var obj = [ { school: { name: 'abc', students: [ { class: 'A', name: 'jhon', }, { class: 'B', name: 'Doe', }, ], }, }, { school: { name: 'XYZ', students: [ { class: 'C', name: 'Cena', }, { class: 'B', name: 'Big show', }, ], }, }];
var result = Object.values(obj.reduce((acc, {school})=>{
acc['schoolname'] = [...(acc['schoolname'] || []), school.name];
school.students.forEach(s=>{
Object.entries(s).forEach(([k,v])=>{
acc[k] = [...(acc[k] || []), v];
});
});
return acc;
},{}));
console.log(result);
Even though this is already answered, I want to share my approach.
It you are able to add a dependency, JSONata is well worth, and it can be used not only to query but also to transform objects with fairly simple queries, that most of the time are way easier to read and understand than regular reducers or maps.
Using JSONata your code will look like this:
jsonata('[ [ $.school.name], [ $.school.students.class ], [ $.school.students.name ] ]').evaluate(obj);
https://try.jsonata.org/zqqQNjYmx
Using the builtin Array methods.
schoolNames =obj.map(function(school){return school.school.name})
students = obj.map(function(school){return school.school.students}).flat()
studentNames = students.map(function(student){return student.name})
studentClass = students.map(function(student){return student.class})

Lodash - Sort by position in array

I have an array of objects
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
and an array
let sorter = ['second', 'third', 'first']
I would like to use lodash sorting method to sort my objects according to their position in sorter.
So that the output would be
let mySortedArray = [
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
},
{
id: 'first',
name: 'john',
}
]
Is it possible to do so?
You can achieve this by using map and find:
let myArray = [
{
id: "first",
name: "john"
},
{
id: "second",
name: "Emmy"
},
{
id: "third",
name: "Lazarus"
}
];
let sorter = ["second", "third", "first"];
let mySortedArray = sorter.map(x => myArray.find(y => y.id === x));
console.log(mySortedArray);
Using lodash you can use _.sortBy
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
let sorter = ['second', 'third', 'first']
console.log(_.sortBy(myArray,(i) => {return sorter.indexOf(i.id)}))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
If you want to sort the array in-place, you don't need Lodash, you can easily do it with vanilla JavaScript
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
let sorter = ['second', 'third', 'first']
//create a lookup table (map) to save looking through the array
const sortLookup = new Map();
//populate with element as key - index as value
sorter.forEach((id, index) => sortLookup.set(id, index));
//sort using the indexes of sorter
myArray.sort((a, b) => sortLookup.get(a.id) - sortLookup.get(b.id))
console.log(myArray)
This is using a Map but the same can easily be accomplished with a plain JavaScript Object {}. You don't even need to pre-compute the lookup myArray.sort((a, b) => sorter.indexOf(a.id) - sorter.indexOf(b.id)) would give the exact same output but it would mean that instead of traversing sorter once for a complexity of O(n), you potentially have O(n^m)or O(n^n) (if both arrays are the same length)
Since you have an index array in the case of the sorter you can _.keyBy the main array and then use the sorter to access by index:
let myArray = [ { id: 'first', name: 'john', }, { id: 'second', name: 'Emmy', }, { id: 'third', name: 'Lazarus', } ]
let sorter = ['second', 'third', 'first']
const idMap = _.keyBy(myArray, 'id')
const result = _.map(sorter, x => idMap[x])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
This should perform better since you only do the idMap once and then access it by index.

Append array into the array of Objects

I have an array of objects as shown below.
var myArray = [
{
Data: '455',
Note: 'tre',
Id: '4'
},
{
Data: '456',
Note: 'bre',
Id: '5'
},
{
Data: '457',
Note: 'cre',
Id: '6'
}
];
I also have this array
Percent = [ '10', '20', '30'],
Can someone please let me know how do i add this array elements into the array of objects. tHe expected output is as follows.
var myArray = [
{
Data: '455',
Note: 'tre',
Id: '4',
Percent: '10'
},
{
Data: '456',
Note: 'bre',
Id: '5',
Percent: '20'
},
{
Data: '457',
Note: 'cre',
Id: '6',
Percent: '30'
}
];
Assuming Percent always contains the same number of items as myArray, loop over myArray and assign the correct value from Percent like this:
myArray.forEach(function(object,index) {
object.Percent = Percent[index];
});
Same assumption as #Adam, but using ES6 arrow function feature:
myArray.map((x,i) => x.Percent = percent[i]);
here is a plunker : link
Don't forget to check browser compatibility : here

Categories