I have a payload structure to add datas into db, each object have name with child array, db should add each object with parent id. how to handle these array in loop adding data in database?
payload structure:
{
"name": "food",
"child_categories": [
{
"name": "non-frozen",
"child_categories": [
{
"name":"non-branded",
"child_categories": [
{
"name":"food-grains",
"child_categories": [
{
"name":"rice"
},
{
"name": "atta"
},
{
"name": "maida"
},
{
"name": "sooji"
},
{
"name":"ragi"
},
{
"name": "jower"
},
{
"name": "bajra"
}
]
},
{
"name":"salt&spices",
"child_categories": [
{
"name":"whole-spices"
},
{
"name":"grounded-spices"
}
]
},
{
"name":"dried-condiments",
"child_categories": [
{
"name":"salt"
},
{
"name":"powders"
},
{
"name":"sugar"
},
{
"name":"jaggery"
}
]
},
{
"name": "edible-oil&ghee"
},
{
"name": "lentils",
"child_categories":[
{
"name":"all-dals"
},
{
"name":"all-rajma"
},
{
"name":"chanas"
},
{
"name":"millets"
},
{
"name":"soya"
}
]
}
]
},
{
"name":"branded",
"child_categories": [
{
"name":"food-grains",
"child_categories": [
{
"name":"rice"
},
{
"name": "atta"
},
{
"name": "maida"
},
{
"name": "sooji"
},
{
"name":"ragi"
},
{
"name": "jower"
},
{
"name": "bajra"
}
]
},
{
"name":"salt&spices",
"child_categories": [
{
"name":"whole-spices"
},
{
"name":"grounded-spices"
}
]
},
{
"name":"dried-condiments",
"child_categories": [
{
"name":"salt"
},
{
"name":"powders"
},
{
"name":"sugar"
},
{
"name":"jaggery"
}
]
},
{
"name": "edible-oil&ghee"
},
{
"name": "lentils",
"child_categories":[
{
"name":"all-dals"
},
{
"name":"all-rajma"
},
{
"name":"chanas"
},
{
"name":"millets"
},
{
"name":"soya"
}
]
},
{
"name":"snacks&cereals",
"child_categories":[
{
"name":"biscuits"
},
{
"name":"cookies"
},
{
"name":"bhujia"
},
{
"name":"mixture"
}
]
},
{
"name":"packaged-raw",
"child_categories":[
{
"name":"noodles"
},
{
"name":"pasta"
},
{
"name":"macaroni"
},
{
"name":"spreads"
},
{
"name":"sauces"
},
{
"name":"ready-to-eat"
},
{
"name":"chocs"
},
{
"name":"pickles&chutney"
}
]
}
]
}
]
}
]
}
Each categories have sub categories,with up level parent_id, once first level category added, it should take that id, add it into child category. example structure below
{
_id: "1",
parent_category_id: null, // 1st level category
name:"food"
}
{
_id:2,
parent_category_id: 1,
name: "non-frozen"
}
{
_id: 3,
parent_category_id: 2,
name: "non-branded"
}
{
_id: 4,
parent_category_id: 3,
name: "food-grains"
}
and so on...
let payload = req.payload
let obj1 = {
"name": payload.name,
"parent_category_id": null,
"created_by": userId,
"updated_by": userId
}
let parent_category = await Category.create(obj1)
if (!!payload.childCategories){
payload.childCategories.forEach(async item => {
if(!!item){
let obj2 = {
"name": item.name,
"parent_category_id": parent_category._id,
"created_by": userId,
"updated_by": userId
}
let parent_category1 = await Category.create(obj2)
if (!!item.childCategories){
payload.childCategories.forEach(async item1 => {
let obj3 = {
"name": item1.name,
"parent_category_id": parent_category1._id,
"created_by": userId,
"updated_by": userId
}
let parent_category2 = await Category.create(obj3)
})
}
}
})
}
My quick thought was to solve the problem with the recursive function. It can be solved in other ways as well. But I like recursive functions. They are legible.
async function addCategory(payload, parent = null) {
const category = await Category.create({
name: payload.name,
parent_category_id: parent ? parent.id : null,
created_by: userId,
updated_by: userId
});
if(Array.isArray(payload.child_categories)) {
for(const child of payload.child_categories) {
addCategory(child, category);
}
}
}
Related
I'm using mongoose.
Just like 'Mysql Join',
I want to get the data that merge the parents and children collection below.
Parent
[
{
type: "A",
results: [
{
"id": 111111
},
{
"id": 222222
}
]
},
{
type: "B",
results: [
{
"id": 333333
},
{
"id": 444444
}
]
}
]
Child
[
{
dataId: 111111,
results: [
{ "status": { key: "value" } }
]
},
{
dataId: 222222,
results: [
{ "status": { key: "value" } }
]
},
{
dataId: 333333,
results: [
{ "status": { key: "value" } }
]
},
{
dataId: 444444,
results: [
{ "status": { key: "value" } }
]
},
]
Because ObjectId cannot be inserted,
it seems that it cannot be processed using the population method.
I want to merge the two data like Join in MySQL.
like below
Parent.find()
[
{
type: "A",
results: [
{
"id": 111111,
results: [
{ "status": { key: "value" } }
]
},
{
"id": 222222,
results: [
{ "status": { key: "value" } }
]
}
]
},
{
type: "B",
results: [
{
"id": 333333,
results: [
{ "status": { key: "value" } }
]
},
{
"id": 444444,
results: [
{ "status": { key: "value" } }
]
}
]
}
]
You can use this query:
$unwind to get every result from the array to merge with the Child dataid.
$lookup which is the "join" in mongodb. Here query is mergin field id into results from the Parent with dataId from the Child.
$unwind again because $lookup creates an array.
$group to group the values according the id.
$project (this stage is optional) to not shown fields you don't want.
yourParentModel.aggregate([
{
"$unwind": "$results"
},
{
"$lookup": {
"from": "Child",
"localField": "results.id",
"foreignField": "dataId",
"as": "child_results"
}
},
{
"$unwind": "$child_results"
},
{
"$group": {
"_id": "$_id",
"type": {
"$first": "$type"
},
results: {
"$push": "$child_results"
}
}
},
{
"$project": {
"_id": 0,
"results._id": 0
}
}
])
Example here
you could do this from javascript directly
first you get the parent from mongoDB
( use mongoose find method)
let parents = [
{
type: "A",
results: [
{
id: 111111,
},
{
id: 222222,
},
],
},
{
type: "B",
results: [
{
id: 333333,
},
{
id: 444444,
},
],
},
];
then you get the child from the database
let children = [
{
dataId: 111111,
results: [{ status: { key: "value" } }],
},
{
dataId: 222222,
results: [{ status: { key: "value" } }],
},
{
dataId: 333333,
results: [{ status: { key: "value" } }],
},
{
dataId: 444444,
results: [{ status: { key: "value" } }],
},
];
and the treatement to merge the parents with the children will be something like this
for (let parent of parents) {
for (let objectId of parent.results) {
for (let child of children) {
if (child.dataId === objectId.id) {
objectId.results = child.results;
break;
}
}
}
}
I have a list of team objects which consists team name, reported by and list of statuses for each day of that team which I would like to convert it into list of date based objects which contains all teams and its status for the respective date.
I have tried something like this which is not giving expected results.
teams.map(team => ({
day: team.statuses.reduce((acc, it) => it.day),
teams: {
teamName: team.teamName
}
}))
[
{
"teamName":"abc",
"reportedBy": "user1",
"statuses":[
{
"day":"10/12",
"status":"green"
},
{
"day":"10/11",
"status":"green"
},
{
"day":"10/09",
"status":"green"
}
]
},
{
"teamName":"xyz",
"reportedBy": "user2",
"statuses":[
{
"day":"10/12",
"status":"red"
},
{
"day":"10/11",
"status":"red"
},
{
"day":"10/09",
"status":"red"
}
]
}
]
Expected Output:
[
{
"day": "1012",
"teams": [
{
"teamName": "abc",
"reportedBy": "user1",
"status": "green"
},
{
"teamName": "xyz",
"reportedBy": "user2",
"status": "red"
}
]
},
{
"day": "1011",
"teams": [
{
"teamName": "abc",
"reportedBy": "user1",
"status": "green"
},
{
"teamName": "xyz",
"reportedBy": "user2",
"status": "red"
}
]
},
{
"day": "1009",
"teams": [
{
"teamName": "abc",
"reportedBy": "user1",
"status": "green"
},
{
"teamName": "xyz",
"reportedBy": "user2",
"status": "red"
}
]
}
]
I don't think reduce is the best option here. I think it's better to create an empty array and populate as you go:
let input = [
{
"teamName":"abc",
"reportedBy": "user1",
"statuses":[
{
"day":"10/12",
"status":"green"
},
{
"day":"10/11",
"status":"green"
},
{
"day":"10/09",
"status":"green"
}
]
},
{
"teamName":"xyz",
"reportedBy": "user2",
"statuses":[
{
"day":"10/12",
"status":"red"
},
{
"day":"10/11",
"status":"red"
},
{
"day":"10/09",
"status":"red"
}
]
}
];
let output = [];
input.forEach(team =>
{
let name = team.teamName;
let reporter = team.reporter
team.statuses.forEach(status =>
{
let dayItem = output.find(item => item.day == status.day);
if(dayItem == null)
{
let newItem = {day: status.day, teams:[{status: status.status, reportedBy: reporter, teamName: name}]};
output.push(newItem);
}
else
{
dayItem.teams.push({status: status.status, reportedBy: reporter, teamName: name})
}
});
});
console.log(JSON.stringify(output));
I have tried something like following.
let dayIndexed = {};
let dayStatuses = [];
teams.forEach(function(team) {
team.statuses.forEach(function(status) {
status.day = status.day.replace(/\//g, '');
if(!dayIndexed[status.day]) {
dayIndexed[status.day] = {
day: status.day,
teams: []
};
dayStatuses.push(dayIndexed[status.day]);
}
dayIndexed[status.day].teams.push({
teamName: team.teamName,
reportedBy: team.reportedBy,
status: status.status
});
});
});
I have this data structure:
{
"_id": "5ebd08794bcc8d2fd893f4a7",
"username": "johan#gmail.com",
"password": "123",
"decks": [{
"cards": [{
"_id": "5ebd08794bcc8d2fd893f4a9",
"planeetnaam": "Venus",
"kleur": "Grijs"
},
{
"_id": "5ebd08794bcc8d2fd893f4aa",
"planeetnaam": "Neptunus",
"kleur": "Paars"
}
],
"_id": "5ebd08794bcc8d2fd893f4a8",
"name": "Planeten"
},
{
"cards": [{
"_id": "5ebd08794bcc8d2fd893f4ac",
"diernaam": "Hond",
"poten": "4"
},
{
"_id": "5ebd08794bcc8d2fd893f4ad",
"diernaam": "Kangoeroe",
"poten": "2"
}
],
"_id": "5ebd08794bcc8d2fd893f4ab",
"name": "Dieren"
}
],
"__v": 0
}
Now i want to add a new property to all the cards in deck with deckname: "Planeten". How do i do this with a mongoose query?
The cards array of deck "Planeten" should look like this after the query
"cards": [{
"_id": "5ebd08794bcc8d2fd893f4a9",
"planeetnaam": "Venus",
"kleur": "Grijs",
"newProp": null
},
{
"_id": "5ebd08794bcc8d2fd893f4aa",
"planeetnaam": "Neptunus",
"kleur": "Paars",
"newProp": null
}
],
EDIT:
This works in Robo3T:
db.getCollection('users').findOneAndUpdate(
{ '_id': ObjectId("5eba9ee0abfaf237f81fb104") },
{ $set: { 'decks.$[deck].cards.$[].newProp': null } },
{ arrayFilters: [{ 'deck._id': ObjectId("5eba9ee0abfaf237f81fb108") } ] }
)
But the server query doesnt edit any data:
User.findOneAndUpdate(
{ '_id': req.session.userid },
{ $set: { 'decks.$[deck].cards.$[].newProp': null } },
{ arrayFilters: [{ 'deck._id': req.params.deckid } ] }, function(err, user){
res.send('test');
})
Thanks in advance
you can use array update operators
the query may look something like that
db.collection.updateOne(
{ _id: <ObjectId> }, // the filter part
{ $set: { 'decks.$[deck].cards.$[].newProp': null } },
{ arrayFilters: [{ 'deck.name': 'Planeten' }] }
)
$[deck] refers to each element in the decks array
$[] is used to update all the elements in the cards array
your function may look something like that
User.updateOne(
{ '_id': req.session.userid },
{ $set: { 'decks.$[deck].cards.$[].newProp': null } },
{ arrayFilters: [{ 'deck.name': 'Planeten' }] })
.then(function (user) {
if (!user) {
res.status(404).send('Er ging helaas iets fout')
} else {
res.status(201).send("Card is toegevoegd");
}
})
hope it helps
I am having a dynamic JSON array in below format,
let main_data = [
{
"client":[
{
"name":"aaaa",
"count":"1",
"filter":{
"type":{
"name":"test3"
}
}
},
{
"name":"bbbb",
"count":"9",
"filter":{
"type":{
"name":"test2"
}
}
}
]
},
{
"compute":[
{
"name":"cccc",
"count":"6",
"filter":{
"type":{
"name":"test"
}
}
}
]
}
]
Here key "name" is unique. When updating a form, I will get an json array like below,
let new_data = [
{
"client":[
{
"name":"bbbb",
"count":"1234",
"type":{
"name":"updated_name"
}
}
}
]
}
]
I need to check the "name" in the json array in "main_data" and remove the existing one and update with the new "updated_data" into the "main_data". (no Jquery please)
Expected output,
let main_data = [
{
"client":[
{
"name":"aaaa",
"count":"1",
"filter":{
"type":{
"name":"test3"
}
}
},
{
"name":"bbbb",
"count":"123",
"filter":{
"type":{
"name":"updated_name"
}
}
}
]
},
{
"compute":[
{
"name":"cccc",
"count":"6",
"filter":{
"type":{
"name":"test"
}
}
}
]
}
]
Is there any way to achive this. Any help would be much appreciated. Thanks in advance.
Try this
let main_data = [{
client: [{
name: "aaaa",
count: "1",
filter: {
type: {
name: "test3"
}
}
},
{
name: "bbbb",
count: "9",
filter: {
type: {
name: "test2"
}
}
}
]
},
{
compute: [{
name: "cccc",
count: "6",
filter: {
type: {
name: "test"
}
}
}]
}
];
let new_data = [{
client: [{
name: "bbbb",
count: "1234",
filter: {
type: {
name: "updated_name"
}
}
}]
}];
const res = main_data.map((item, index) => {
if (item.client) {
const clients = item.client.map(client => {
if (client.name === new_data[0].client[0].name) {
client = new_data[0].client[0];
}
return client;
});
return {
client: clients
};
}
return item;
});
console.log(res);
There may very well be a fancy way to get this done but one can always just find the matching item and replace it. eg.
let main_data = [
{
"client": [
{
"name": "aaaa",
"count": "1",
"filter": {
"type": {
"name": "test3"
}
}
},
{
"name": "bbbb",
"count": "123",
"filter": {
"type": {
"name": "updated_name"
}
}
}
]
},
{
"compute": [
{
"name": "cccc",
"count": "6",
"filter": {
"type": {
"name": "test"
}
}
}
]
}
];
let new_data = [
{
"client": [
{
"name": "bbbb",
"count": "1234",
"type": {
"name": "updated_name"
}
}
]
}
];
console.log("before:" + JSON.stringify(main_data));
newItem = new_data[0]["client"][0];
mainDataList = main_data[0]["client"];
for (i = 0; i < mainDataList.length; i++) {
if (mainDataList[i].name == newItem.name) {
mainDataList[i] = newItem;
}
}
console.log("after:" + JSON.stringify(main_data));
will output
before:[{"client":[{"name":"aaaa","count":"1","filter":{"type":{"name":"test3"}}},{"name":"bbbb","count":"123","filter":{"type":{"name":"updated_name"}}}]},{"compute":[{"name":"cccc","count":"6","filter":{"type":{"name":"test"}}}]}]
after:[{"client":[{"name":"aaaa","count":"1","filter":{"type":{"name":"test3"}}},{"name":"bbbb","count":"1234","type":{"name":"updated_name"}}]},{"compute":[{"name":"cccc","count":"6","filter":{"type":{"name":"test"}}}]}]
Here's a simple way to do this, let's say your new data is at variable newData:
main_data.client.filter(item => item.name === newData.name).push(newData)
Here is my sample Data:
{
"_id": {
"$oid": "5654a8f0d487dd1434571a6e"
},
"ValidationDate": {
"$date": "2015-11-24T13:06:19.363Z"
},
"DataRaw": " WL 00100100012015-08-28 02:44:17+0000+ 16.81 8.879 1084.00",
"ReadingsAreValid": true,
"locationID": " WL 001",
"Readings": {
"pH": {
"value": 8.879
},
"SensoreDate": {
"value": {
"$date": "2015-08-28T02:44:17.000Z"
}
},
"temperature": {
"value": 16.81
},
"Conductivity": {
"value": 1084
}
},
"HMAC":"ecb98d73fcb34ce2c5bbcc9c1265c8ca939f639d791a1de0f6275e2d0d71a801"
}
I am trying to group average values by two hours interval and have the following aggregation query.
Query = [{"$unwind":"$Readings"},
{'$group' : { "_id": {
"year": { "$year": "$Readings.SensoreDate.value" },
"dayOfYear": { "$dayOfYear": "$Readings.SensoreDate.value" },
"interval": {
"$subtract": [
{ "$hour": "$Readings.SensoreDate.value"},
{ "$mod": [{ "$hour": "$Readings.SensoreDate.value"},2]}
]
}
}},
'AverageTemp' : { '$avg' : '$Readings.temperature.value'}, "AveragePH": {"$avg" : "$Readings.pH.value"}, "AverageConduc": {"$avg" : "$Readings.Conductivity.value"}}
, {"$limit":10}]
This gives me an error saying
A pipeline stage specification object must contain exactly one field. and I have done all research but can't get the desired results.
After some formatting, your present aggregation pipeline looks like:
Query = [
{ "$unwind": "$Readings" },
{
'$group' : {
"_id": {
"year": { "$year": "$Readings.SensoreDate.value" },
"dayOfYear": { "$dayOfYear": "$Readings.SensoreDate.value" },
"interval": {
"$subtract": [
{ "$hour": "$Readings.SensoreDate.value"},
{
"$mod": [
{ "$hour": "$Readings.SensoreDate.value" },
2
]
}
]
}
}
},
'AverageTemp' : { '$avg' : '$Readings.temperature.value' },
"AveragePH": { "$avg" : "$Readings.pH.value" },
"AverageConduc": { "$avg" : "$Readings.Conductivity.value" }
},
{ "$limit": 10 }
]
with which mongo is complaining
A pipeline stage specification object must contain exactly one field.
because it's failing to recognise the misplaced fields
'AverageTemp' : { '$avg' : '$Readings.temperature.value' },
"AveragePH": { "$avg" : "$Readings.pH.value" },
"AverageConduc": { "$avg" : "$Readings.Conductivity.value" }
A correct pipeline should have these fields within the $group pipeline stage, so a working pipeline follows:
Query = [
{ "$unwind": "$Readings" },
{
"$group" : {
"_id": {
"year": { "$year": "$Readings.SensoreDate.value" },
"dayOfYear": { "$dayOfYear": "$Readings.SensoreDate.value" },
"interval": {
"$subtract": [
{ "$hour": "$Readings.SensoreDate.value"},
{
"$mod": [
{ "$hour": "$Readings.SensoreDate.value" },
2
]
}
]
}
},
"AverageTemp" : { "$avg" : "$Readings.temperature.value" },
"AveragePH": { "$avg" : "$Readings.pH.value" },
"AverageConduc": { "$avg" : "$Readings.Conductivity.value" }
}
},
{ "$limit": 10 }
]