Array formations - node.js

Here i have a array of objects. I want the each grade as seperate array and inside the array i want the grade based section and subjects.
If teacher is taking a grade i want the schema as which grade they take and what section, inside that what subject they are taking.
var user = [
RowDataPacket { grade_id: 3, subject_id: 3, section_id: 747 },
RowDataPacket { grade_id: 4, subject_id: 3, section_id: 748 },
RowDataPacket { grade_id: 5, subject_id: 3, section_id: 749 },
RowDataPacket { grade_id: 6, subject_id: 3, section_id: 750 },
RowDataPacket { grade_id: 7, subject_id: 3, section_id: 751 },
RowDataPacket { grade_id: 8, subject_id: 3, section_id: 752 },
RowDataPacket { grade_id: 7, subject_id: 4, section_id: 751 }
]
Desired / target schema
let gradeDetails = [{
grade_id: 3,
section_details: [{
section_id: 747,
subject_details: [{subject_id: 3}]
}]
}, {
.
.
.
}, {
grade_id: 7
section_details: [{
section_id: 751,
subject_details: [
{subject_id: 3},
{subject_id: 4}
]
}]
}, {
grade_id: 8,
section_details: [{
section_id: 752,
subject_details: [{subject_id: 3}]
]}
}];

The below code snippet may be one way to achieve the desired result:
Code Sample
const getGradeDetailsArray = (arr = user) => {
const resultArr = [];
for (const grade of (new Set(arr.map(obj => obj.grade_id)))) {
const resObj = {
grade_id: grade,
section_details: arr.filter(
obj => obj.grade_id === grade
).map(
obj => ({
section_id: obj.section_id,
subject_details: [{ subject_id: obj.subject_id }]
})
)
};
resultArr.push(resObj)
};
return resultArr;
};
Explanation
Initialize the result as an empty-array named resultArr
Obtain unique grade_ids by using new Set() and iterate over each grade
For each grade, construct an object to be pushed to the result
grade_id is set to grade
section_details is set as an array filtered by matching grade_id
subect_details is an array with exactly one element (ie, the subject_id).
Return the resultArr
Code Snippet
const user = [
{ grade_id: 3, subject_id: 3, section_id: 747 },
{ grade_id: 4, subject_id: 3, section_id: 748 },
{ grade_id: 5, subject_id: 3, section_id: 749 },
{ grade_id: 6, subject_id: 3, section_id: 750 },
{ grade_id: 7, subject_id: 3, section_id: 751 },
{ grade_id: 8, subject_id: 3, section_id: 752 },
{ grade_id: 7, subject_id: 4, section_id: 751 },
];
const getGradeDetailsArray = (arr = user) => {
const resultArr = [];
for (const grade of (new Set(arr.map(obj => obj.grade_id)))) {
const resObj = {
grade_id: grade,
section_details: arr.filter(
obj => obj.grade_id === grade
).map(
obj => ({
section_id: obj.section_id,
subject_details: [{ subject_id: obj.subject_id }]
})
)
};
resultArr.push(resObj)
};
return resultArr;
};
console.log(getGradeDetailsArray());
const newGetGradeDetails = (arr = user) => (
Object.entries(
arr.reduce((fin, itm) => ({
...fin,
[itm.grade_id]: {
...fin[itm.grade_id],
[itm.section_id]: {
...(fin && fin[itm.grade_id] && fin[itm.grade_id][itm.section_id]
? fin[itm.grade_id][itm.section_id]
: {}
),
subjects: [
...(fin && fin[itm.grade_id] &&
fin[itm.grade_id][itm.section_id] &&
fin[itm.grade_id][itm.section_id].subjects &&
Array.isArray(fin[itm.grade_id][itm.section_id].subjects)
? fin[itm.grade_id][itm.section_id].subjects
: []
),
itm.subject_id
]
}
}
}) ,{})
).map(([kg, vg]) => ({
grade_id: kg,
section_details: Object.entries(vg).map(([kse, vse]) => ({
section_id: kse,
subject_details: vse.subjects.map(su => ({
subject_id: su
}))
}))
}))
);
console.log('\n\tUpdated as per comments noted below\n\n', newGetGradeDetails());
Edit: Added new method to account for changes requested on comments below.

Related

Mongoose DB - Find inside an array

I have the following data inside a mongoose collection:
{
map: 'Sydney',
Postcode: 2000,
mapItems: [
{
team: 'NONE',
teamIcon: 20,
x: 0.6092914,
y: 0.28168318,
flags: 0
},
{
team: 'Alpha',
teamIcon: 33,
x: 0.63026464,
y: 0.41642973,
flags: 0
},
{
team: 'Bravo',
teamIcon: 20,
x: 0.63026464,
y: 0.41642973,
flags: 0
},
{
team: 'Alpha',
teamIcon: 20,
x: 0.63026464,
y: 0.41642973,
flags: 0
}
}
I'm trying to return just the mapItems that have the team as "Alpha" and teamIcon is 33 or 52.
dyDB
.find({
$or: [
{
"mapItems.teamIcon": 33,
},
{
"mapItems.teamIcon": 52,
},
],
$and: [
{
"mapItems.teamId": "Alpha" },
},
],
})
.then((data) => {
for (const dyn of data) {
console.log(dyn);
}
});
But it just returns everything and doesn't seem to filter it. I'm not sure what else to try. Can anyone give some pointers?
You have to use or inside and:
dyDB.find({
mapItems: {
$elemMatch: {
$and: [
{ $or: [{ teamIcon: 52 }, { teamIcon: 33 }] },
{ team: "Alpha" },
],
},
},
})
.then((data) => {
for (const dyn of data) {
console.log(dyn);
}
});

Filtering documents in mongodb and nodejs

Data in the database is stored as given below. if I do a query like
const food = await Nutrition.find()
Then I get this in response
[
{
_id: 6035ff4778b1893fa5e8080f,
name: 'apple',
weight: 100,
unit: 'gram',
carbohydrates: 14,
calories: 52,
proteins: 0.3,
fats: 0.2,
__v: 0
},
{
_id: 6036011437035541b0bd5e0a,
name: 'banana',
weight: 100,
unit: 'gram',
carbohydrates: 23,
calories: 89,
proteins: 11,
fats: 0.39,
__v: 0
},
{
_id: 6036011437035541b0bd5e0b,
name: 'melon',
weight: 100,
unit: 'gram',
carbohydrates: 45,
calories: 100,
proteins: 11,
fats: 0.39,
__v: 0
}
]
I have this controller in nodejs which fetch food nutrition from the database
const Nutrition = require('../model/nutritionalFacts')
exports.nutritionFacts = (async (req,res) =>{
try {
const food = await Nutrition.find()
console.log(food);
} catch (error) {
console.log('Error occurred',error.message);
}
})
Now in request (req), req.body is coming as
[
{ name: 'apple', id: 0, selected: true, weight: 100, unit: 'gram' },
{ name: 'banana', id: 1, selected: true, weight: 100, unit: 'gram' }
]
Now I want to filter only those documents from the database whose name matches with the name coming in an array of objects from the client as mentioned above without looping, just using MongoDB query syntax. Can we do this?
You can use $in operator to achieve that. You need to change your find method as below
var namesArr = ["banana", "melon"];
db.Nutrition.find({ "name" : { "$in": namesArr } })
Then the results for the sample above:
{
"_id" : ObjectId("60361058cce08c8b8ebe0509"),
"name" : "banana",
"weight" : 100,
"unit" : "gram",
"carbohydrates" : 23,
"calories" : 89,
"proteins" : 11,
"fats" : 0.39,
"__v" : 0
}
{
"_id" : ObjectId("60361058cce08c8b8ebe050a"),
"name" : "melon",
"weight" : 100,
"unit" : "gram",
"carbohydrates" : 45,
"calories" : 100,
"proteins" : 11,
"fats" : 0.39,
"__v" : 0
}
Try this
const Nutrition = require('../model/nutritionalFacts');
exports.nutritionFacts = (async (req, res) => {
try {
if (!Array.isArray(req.body.payload)) {
throw new Error("Invalid payload!") // or whatever error message u want!
}
const names = payload.map(item => item.name); // u cannot avoid this looping of payload!
const conditions = {
name: { $in: names }
};
const food = await Nutrition.find(conditions);
console.log(food);
} catch (error) {
console.log('Error occurred', error.message);
}
})

$lookup on object array with table

I have data object that contains array. And I have providers table.
if array's Id should equals to provider's table id Id == id
if id is repeated take the repeated count as membersCounts else membersCounts = 0
Add the membersCounts with data object
data object
const data = {
Milk: [
{
Id: 1,
name: 'a'
},
{
Id: 2,
name: 'b'
},
{
Id: 3,
name: 'c'
},
{
Id: 4,
name: 'd'
},
{
Id: 52,
name: 'e'
}
],
Grocery: [
{
Id: 8,
name: '2a'
},
{
Id: 22,
name: '2b'
},
{
Id: 32,
name: '2c'
},
{
Id: 42,
name: '2d'
}
]
}
providers table
const providers = [
{
id: 1,
status: 'active'
},
{
id: 1,
status: 'active'
},
{
id: 1,
status: 'active'
},
{
id: 1,
status: 'active'
},
{
id: 4,
status: 'active'
},
{
id: 2,
status: 'active'
},
{
id: 3,
status: 'active'
},
{
id: 3,
status: 'active'
},
{
id: 52,
status: 'active'
},
{
id: 1,
status: 'active'
}
]
here javascript code
this code is working good but I want perform this with mongodb queries. So that performance is good .
Is possible to do with mongodb query. I need to covert the javascript code to mongodb query.
getMembersWithVendors(data, providers) {
for (var key in data) {
var arr = data[key]
arr.forEach((element) => {
element.memberCounts = 0
element.new = true
providers.map((el) => {
if (element._id == el.vendorId) {
(element.memberCounts = element.memberCounts + 1),
(element.new = false)
}
})
})
}
return data
}
output
{ Milk:
[ { Id: 1, name: 'a', memberCounts: 5 },
{ Id: 2, name: 'b', memberCounts: 1 },
{ Id: 3, name: 'c', memberCounts: 2 },
{ Id: 4, name: 'd', memberCounts: 1 },
{ Id: 52, name: 'e', memberCounts: 1 } ],
Grocery:
[ { Id: 8, name: '2a', memberCounts: 0 },
{ Id: 22, name: '2b', memberCounts: 0 },
{ Id: 32, name: '2c', memberCounts: 0 },
{ Id: 42, name: '2d', memberCounts: 0 } ] }
Thanks !!
this code is working good but I want perform this with mongodb queries. So that performance is good
That is not good idea to do all the operations in query, it may cause performance issues, because your input data is so big, but you can improve some things,
$group by query id and get count, this will return unique ids and its total counts
let providers = await db.providers.aggregate([
{
$group: {
_id: "$id",
count: { $sum: 1 }
}
}
]);
iterate loop of object's array
find from providers on the base of id
get count from filtered document
for (let key in data) {
data[key].forEach(e => {
let p = providers.find(p => p._id === e.Id);
e.memberCounts = p ? p.count : 0;
})
}
console.log(data);
Repl Playground

Merging Area objects based on Similar Id

I am getting this output :
"Area":
[{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
}]
},
{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
}]
}]
But I want it merging to be like this :
"Area":[{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
},
{
"AssetId":someothervalue,
"ActionId":someothervalue,
}]
You could use groupBy of loadash. Code will look something like this
const {groupBy} = require("lodash");
const input = [
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 7,
AssetId: 1,
Asset: "TubeLight",
ActionId: 1,
Action: "Clean",
TenantChargeBack: 0,
TenantChargeType: "%",
TenantChargeValue: 25,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 8,
AssetId: 1,
Asset: "Bed",
ActionId: 3,
Action: "Repair",
TenantChargeBack: 1,
TenantChargeType: "%",
TenantChargeValue: 50,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 3,
AreaName: "Bathroom",
Data: [
{
Id: 9,
AssetId: null,
Asset: null,
ActionId: 2,
Action: "Replace",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 100,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 3,
AreaName: "Bathroom",
Data: [
{
Id: 10,
AssetId: 6,
Asset: "Jaar",
ActionId: 3,
Action: "Repair",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 100,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 11,
AssetId: null,
Asset: null,
ActionId: 1,
Action: "Clean",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 50,
Notes: "",
FilePath: null
}
]
}
];
const groupedData = groupBy(input, i => i.AreaId);
const result = Object.keys(groupedData).map(j => {
const combined = groupedData[j];
return combined.reduce((a, b) => {
return {
"AreaId": a.AreaId,
"AreaName": a.AreaName,
"Data": a.Data.concat(b.Data)
};
})
});
console.log(JSON.stringify(result));

Find objects in deep Mongo DB docs

I've got a Mongo DB doc with a teams array. All the objects in the teams array contain a user_ids array. How do I find all documents containing a team where user_ids contains a specific Object Id? I'm using Mongoose with Node.
This is the doc structure. How would I eg find all docs with Object Id "56a60da2351195cc6be83799" in any of the teams?
{
"_id" : ObjectId("56a60da3351195cc6be8379c"),
"session_id" : ObjectId("56a60da2351195cc6be83798"),
"teams" : [
{
"score" : 0,
"user_ids" : [
ObjectId("56a60da2351195cc6be83799")
]
},
{
"score" : 0,
"user_ids" : [
ObjectId("56a60da2351195cc6be8379a")
]
}
],
"created_at" : ISODate("2016-01-25T11:57:23.006Z") }
Thanks
Let's say your collection name is collection, try:
db.collection.find({"teams.user_ids": ObjectId("56a60da2351195cc6be83799")})
It will find a document, if exists matching user_ids
For nested arrays the $in operator will be a good choice (see documentation).
I tried to reproduce your settings and created a simple model:
var testSchema = mongoose.Schema({
session_id: { type: Number },
teams : [
{
score: { type: Number },
user_ids: [{ type: Number }]
}
]
})
var Test = mongoose.model("Test", testSchema);
Inserted demo data:
var test1 = new Test({
session_id: 5,
teams: [
{ score: 5, user_ids: [ 1, 2, 4] },
{ score: 3, user_ids: [ 2, 7, 9 ] },
{ score: 1, user_ids: [ 3 ] },
]
});
test1.save(function(err, t1) { console.log("test", err, t1); });
var test2 = new Test({
session_id: 1,
teams: [
{ score: 5, user_ids: [ 11, 12 ] },
{ score: 3, user_ids: [ 1, 9 ] },
]
});
test2.save(function(err, t2) { console.log("test", err, t2); });
The query to get all objects with a userId of 2 would look like:
Test.find({ "teams.user_ids": { $in: [2] }}, function(err, res) {
console.log("query:", err, res);
});
Or in a more mongoose way of reassembling queries:
Test.find()
.where('teams.user_ids')
.in([2])
.then(result => { console.log(result); })
.catch(err => { console.log(err); });

Resources