I have an array that looks like this:
[
{
"children": [
"5efa29058a3e8a3efc45c11a",
"5efa29158a3e8a3efc45c11b"
],
"_id": "5efa29b88a3e8a3efc45c11f",
"tabText": "foo",
"headerText": "foobar",
"__v": 0
},
{
"children": [
"5efa29228a3e8a3efc45c11c",
"5efa292c8a3e8a3efc45c11d",
"5efa29338a3e8a3efc45c11e"
],
"_id": "5efa29ea8a3e8a3efc45c120",
"tabText": "Foo2",
"headerText": "foobar2",
"__v": 0
}
]
For each "children" array on each object I need to take the childs id, look it up in the database, and replace the id string with an object containing the info from the database.
Mongoose Models:
Model1:
const { Schema, model } = require('mongoose')
const Tab = model('tab', new Schema({
tabText: String,
headerText: String,
children: Array
}))
module.exports = Tab
Model2:
const { Schema, model } = require('mongoose')
const Child = model('child', new Schema({
icon: String,
name: String,
description: String
}))
module.exports = Child
The models should be defined like this to form a relationship.
Model1:
const { Schema, model } = require('mongoose')
const Tab = model('Tab', new Schema({
tabText: String,
headerText: String,
children: [{ type: Schema.Types.ObjectId, ref: 'Child' }],
}))
module.exports = Tab
Model2:
const { Schema, model } = require('mongoose')
const Child = model('Child', new Schema({
icon: String,
name: String,
description: String
}))
module.exports = Child
Now the children will reference the ids of Child documents.
And when you want to populate them you can use:
await Tab.findOne().populate('children')
You just need to map over the array twice:
// First: map over each element in the array.
const newArray = array.map(arrElement => {
// Now arrElement is just one of our array elements.
// Then we can map over each element of the arrElement.children
// to get each id separately.
return arrElement.children.map(id => {
// Do stuff with the id...
// Make sure to return your new object from this function.
})
})
This is also a good case for Promise.all so you can run the queries in parallel
await Promise.all(
input.map(async (item) => {
return {
...item,
children: await Promise.all(
item.children.map(async (childId) => {
return await getItemFromDatabase(childId);
})
),
};
})
);
In order to replace each string in a Array. Here is a standard way of doing this.
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map'
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
Related
I'm writing a back code using NodeJs to fetch some data from backend, I want dataBase data to be like this
like this:
data = [{
name: "Admin",
id: '1',
children: [
{ name: "Admin", id: "1" },
{ name: "groupe1", id: "2" },
{
name: "groupe2", id: "1455", children: [
{ name: "groupe2", id: "1455" },
{ name: "gro", id: "5444" },
{ name: "hhrr", id: "45" }
]
}
]
}]
the idea is simple we have a list of group each group has a parent I want to display all the groups list in an hierarchical way the top one of the tree is done
Some groups are parents and groups in the same time and some others are only groups if the group is not parent we add an object with its name and ID in the array of children of his parent
if this groups is a parent that's mean it has children we add an object with its ID and name in the array of children of his parents, and we add property children for the object which is array named children with for the first time an object with the name and the id of the group etc...
i tryed to do this but it did not work
const getParentsByType = async ({ name, _id }) => {
let parentResult = [
{
id: _id,
name: name,
children: [
{
id: _id,
name: name,
},
],
},
];
parentResult= await findParent(_id, parentResult[0].children, 0);
return parentResult;
};
const findParent = async (parentId, parentResult, itemPos) => {
let children = await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id');
for (let i = 0; i < children.length; i++) {
let childrenList = await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id');
if (childrenList.length != 0) {
parentResult.push(buildParentWithChild(children[i]._id, children[i].name));
findParent(children[i]._id,parentResult.children[i],itemPos++)
} else {
parentResult.push(buildParent(children[i]._id, children[i].name));
}
}
return parentResult
};
and this the model of the data base
const Group = mongoose.Schema({
name: {
type: String,
required: true,
},
status: {
type: Boolean,
required: true,
},
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Group',
},
});
i had two days trying to resolve tis but with no result
i need some helps and Thank you
Try parsing your returned data. It validates your data as objects i dont see any problem with your function regardless i still have no idea what format your a trying to build.
let children = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: parentId, status: true }).select('name _id')));
let childrenList = JSON.parse(JSON.stringify(await Models.GroupModel.find({ parent: children[i]._id, status: true }).select('name _id')));
If I understand you right, you want to convert the array returned by Models.GroupModel.find, and which looks like
var dbresult = [
{_id: "1", parent: null, name: "one"},
{_id: "2", parent: "1", name: "two"}
];
into a hierarchical structure. This can be done with a function that adds all children of a given parent p, including, recursively, their children. Like the following:
function children(p) {
var result = [];
for (r of dbresult) if (r.parent === p) {
var row = {_id: r._id, name: r.name};
var chld = children(r._id);
if (chld.length > 0) row.children = chld;
result.push(row);
}
return result;
}
console.log(JSON.stringify(children(null)));
Note that this approach requires only one database access (to fill the dbresult) and is therefore probably faster than your findParent function.
im trying to create a seprate route in my api for a subArray from a nested array. using expressJs.
categories array:
const Categories = [
{
_id: 's654fs54s6d4f'
title: 'category 1',
SubCats: [
{
_id: 'jhgfsf68746'
name: 'subcat 1',
image: '/assets/images/vr-box-6203301_1920.jpg',
},
{
_id: 'vb40n5b4vn'
name: 'subcat 2',
image: '/assets/images/galaxy-s20_highlights_kv_00.jpg',
},
]
},
]
categoryModel:
import mongoose from 'mongoose'
const Catschema = mongoose.Schema({
name: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
})
const CategorySchema = mongoose.Schema(
{
title: {
type: String,
required: true,
},
SubCats: [Catschema]
},
{
timestamps: true,
}
)
const Category = mongoose.model('Category', CategorySchema)
export default Category
categoryController:
this would return the whole array
const getCategories = asyncHandler(async (req, res) => {
const categories = await Category.find({})
res.json(categories)
})
i want to return 'SubCats' array.
tried this but getting "SubCats is not defined".
const getSubCategories = asyncHandler(async (req, res) => {
const subcategories = await Category.find({SubCats})
res.json(subcategories)
})
find() returns an array and it takes in an object to query the db. In your question you used Category.find({SubCats}) which is Category.find({SubCats: SubCats}), which SubCats is not defined.
I think what you are looking for is Category.find().select('SubCats'), this will return an array of Categories with SubCats only.
I wanted to create a schema , with multiple object id with each object id containing a Number.
Like for this data,
[ "user": [["collection1",1], ["collection2", 3], ["collection4": 4]
where user is a user object id, and collection1, collection2 .... are collection object id, and other are just number.
const derivedSchema = new mongoose.Schema(
{
user: {type: ObjectId, ref: "User"},
collections: {type: [ObjectId], ref="collection"}],
);
I tried to change like put [ObjectId, Number] if it would look like my data
and tried to save as like this
let collected = new derivedSchema({
"user": uid,
"collections": [cid, 12],
})
collected.save()
where cid is collectionid, uid is userid , 12 number, i passed through in for loop.
But it is not working.
Is there any way to solve this ?
Thank you
At end result i should show like
[
"user1": { ["col1",1], ["col2", 5]},
"user2": { ["col1",55], ["col2", 35]},
]
Any idea would be really helpful?
var mongoose = require('mongoose');
var Schema=mongoose.Schema;
const derivedSchema = new mongoose.Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
collections:{
type:[Schema.Types.ObjectId],
ref:"collection"
}
);
const events = [
[{
createdAt: "2021-12-06T16:32:59.260Z"
location: "Off-Site"
name: "Viewing"
}],
[{
createdAt: "2021-12-06T16:32:59.260Z"
...
}],
..........
]
Hi I have question. From the above can i be able to convert the data to somethin like
const events = [
{
createdAt: "2021-12-06T16:32:59.260Z"
location: "Off-Site"
},
{
createdAt: "2021-12-06T16:32:59.260Z"
...
},
..........
]
if anyone knows please answer
Use Array.flat method
The flat() method creates a new array with all sub-array elements concatenated into it recursively up to the specified dept
const arr = [[1,2,3],[4,5]];
const res = arr.flat()
console.log(res)
For example, I have a schema as below.
const packSchema = new mongoose.Schema({
company: [
name: {type: String},
realName: {type: String, default: ''}
]
})
So I can save a JSON data as below.
[{
"name": "abc",
"realName": "efg"
}]
But when the data doesn't have realName, I want that realName gets data from his own name.
For example, I request this array from ajax call,
[{
"name": "KA"
},
{
"name": "MC"
}]
when I save this object, the result in mongoDB is as below.
[{
"name": "KA",
"realName": "KA"
},
{
"name": "MC",
"realName": "MC"
}]
I think the solution using 'set' option in schema.
function duplicate(){
}
const packSchema = new mongoose.Schema({
company: [
name: {type: String},
realName: {type: String, set: duplicate}
]
})
But I don't know how it can get 'name' data from his own element of array.
Should I use 'for' loop this? or is there other solution?
Thank you for reading it.
The this inside of your function will get bound to the object which you're creating. As a result, you'll be able to use:
function duplicate(v){
return v === undefined ? this.name : v;
}
Above, if the value for realName (ie: v) is undefined, then you'll return this.name, which is the name of the object you're inserting/creating. Otherwise, if realName is already set, it will use that value.
Convert company into sub schema and use a pre save hook to update realname
const companySchema = mongoose.Schema({
name: String,
realName: String
})
companySchema.pre('save',function(next) {
if(!this.realName)
this.realName = this.name
next();
})
const packSchema = mongoose.Schema({
company: [companySchema]
})
const Pack = mongoose.model('Pack', packSchema);