Getting second level nested object inside array of objects mongodb - javascript

My database looks like this:
[
{
"title": "man",
"articlesType": [
{
"title": "shoes",
"articles": [
{
"title": "shoes1",
"id": "randomId"
},
{
"title": "shoes2",
"id": "alsoRandomId"
}
]
}
]
},
{
"title": "woman",
"articlesType": [
{
"title": "pants",
"articles": [
{
"title": "pants1",
"id": "anotherRandomId"
},
{
"title": "pants1",
"id": "justId"
}
]
}
]
}
]
I expect something like this: , is it possible to get whole object in this nested just using an ID?
{
"title": "shoes2",
"id": "alsoRandomId"
}
I found this, but does not work for me

You can try an aggregation pipeline using double $unwind to deconstruct the array twice and then filter by your desired id (I'm assuming you want to match by the id).
And the last step, $project is to output the result in the same way as you want.
db.collection.aggregate([
{
"$unwind": "$articlesType"
},
{
"$unwind": "$articlesType.articles"
},
{
"$match": {
"articlesType.articles.id": "alsoRandomId"
}
},
{
"$project": {
"title": "$articlesType.articles.title",
"id": "$articlesType.articles.id"
}
}
])
Example here

Related

How to update nested object in array (Mongoose/MongoDB)

I've been struggling to get my around how to update a object in a nested array with a particular id. I've attempted to implement $set as shown below. I want to be able to update the task with an _id of 62ff74bfe80b11ade2d34455 with the data from the request body.
{
"_id": "62fa5aa25778ec97bc6ee231",
"user": "62f0eb5ebebd0f236abcaf9d",
"name": "Marketing Plan",
"columns": [
{
"name": "todo",
"_id": "62fa5aa25778ec97bc6ee233",
"tasks": [
{ ====> here
"title": "Task Four",
"description": "This is task four",
"subtasks": [
{
"name": "wash dshes",
"completed": false,
"_id": "62ff74bfe80b11ade2d34456"
},
{
"name": "do homework",
"completed": false,
"_id": "62ff74bfe80b11ade2d34457"
}
],
"_id": "62ff74bfe80b11ade2d34455"
}
]
},
{
"name": "doing",
"_id": "62fa5aa25778ec97bc6ee234",
"tasks": []
},
{
"name": "done",
"_id": "62fa5aa25778ec97bc6ee235",
"tasks": []
}
],
"__v": 0
}
const updatedTask = await Board.findOneAndUpdate(
{
"columns.tasks._id": req.params.id,
},
{ $set: { "columns.$.tasks": req.body } },
{ new: true }
);
You can use the positional operator in combination with an arrayfilter. Here's an example how you'd update a specific field of the relevant task:
db.collection.update({
"columns.tasks._id": req.params.id
},
{
"$set": {
"columns.$[].tasks.$[t].title": "it works"
}
},
{
"arrayFilters": [
{
"t._id": req.params.id
}
]
})
You can also try this on mongoplayground.
If you're looking for a way to replace the matching task object itself you can do:
db.collection.update({
"columns.tasks._id": req.params.id
},
{
"$set": {
"columns.$[].tasks.$[t]": req.body
}
},
{
"arrayFilters": [
{
"t._id": req.params.id
}
]
})

MongoDb update with ElemMatch

I have a collection that has document structure like following:
Mongo PlayGround
{
"basicDetails": {
"id": "1",
"name": "xyz"
},
"tasks": [{
"id": "10",
"name": "task10",
"subtasks": [{
"id": "120",
"name": "subTask120",
"description": "ABC"
}]
}]
}
As you can see, each document has basicDetails object and a tasks array. Each task contains some properties of its own and a subtasks array.
I want to update subtasks's description from ABC to XYZ
where root level id is 1, task'id is 10 and subTasks.id =120
How do I do so?
I know I could find correct document via:
db.collection.find({
"basicDetails.id": "1",
"tasks": {
"$elemMatch": {
"id": "10",
"subtasks": {
"$elemMatch": {
"id": "120"
}
}
}
}
})
But how do I update it? I want to update only one single property of a single subtasks i.e description
To update nested arrays, the filtered positional operator $[identifier] identifies the array elements that match the arrayFilters conditions for an update operation.
Try the following query to $set in nested array:
db.collection.updateOne({
"basicDetails.id": "1"
},
{
"$set": {
"tasks.$[tasks].subtasks.$[subtasks].description": "XYZ"
}
},
{
"arrayFilters": [
{
"tasks.id": "10"
},
{
"subtasks.id": "120"
}
]
})
MongoDB Playground

Concatenating child array to parent

Right now I have an array of object with children that also have an array of objects.
[
{
"code": "mock-code",
"name": "mock-name",
"children": [
{
"code": "mock-child-code",
"name": "mock-child-name",
},
{
"code": "mock-child-code",
"name": "mock-child-name",
},
],
},
{
"code": "mock-code",
"name": "mock-name",
"children": [],
},
{
"code": "mock-code",
"name": "mock-name",
"children": [
{
"code": "mock-code",
"name": "mock-name",
}
],
}
]
I want to extract the children array and concat them to the parent array like below.
[
{
"code": "m1",
"name": "mock-name",
"children": [
{
"code": "mc-1",
"name": "mn-1",
},
{
"code": "mc-2",
"name": "mn-2",
},
],
},
{
"code": "m2",
"name": "mock-name",
"children": [],
},
{
"code": "mm3",
"name": "mock-name",
"children": [
{
"code": "mc-3",
"name": "mn-3",
}
],
}
{
"code": "mc-1",
"name": "mn-1",
},
{
"code": "mc-2",
"name": "mn-2",
},
{
"code": "mc-3",
"name": "mn-3",
}
]
What are someways to do this. I'm currently looping though the child array creating a new array checking if it's not empty. It all seems a bit messy. Is there a clean way to do this?
let fullList = New Array()
parentData.forEach(element => {
if (!!element.children.length) {
fullList.push(element.children);
}
});
return parentData.concat(fullList);
This isn't giving me the desired results since it's adding another array to the parent object but this is where I am at.
const newArray = originalArray.flatMap(element => [element, ...element.children])
This should do it, and as a bonus will preserve the order (parent1, parent1's children, parent2, parent2's children etc.)
Of course, this works if you have only one level of nesting. If you have greater depth level, that would be a bit more complex, probably using Array.prototype.reduce().

How can I get to the last level of a json nest and format the output dynamically?

I have this json:
[
{
"name": "MARVEL",
"superheroes": "yes"
},
{
"name": "Big Bang Theroy",
"superheroes": "NO",
"children": [
{
"name": "Sheldon",
"superheroes": "NO"
}
]
},
{
"name": "dragon ball",
"superheroes": "YES",
"children": [
{
"name": "goku",
"superheroes": "yes",
"children": [
{
"name": "gohan",
"superheroes": "YES"
}
]
}
]
}
]
I know how to loop and go through it but I need an output like this:
[
{
"name": "MARVEL",
"answer": [
{
"there_are_superheroes": "YES"
}
]
},
{
"name": "Big Bang Theroy",
"answer": [
{
"there_are_superheroes": "NO",
"new_leaft": [
{
"name": "sheldon",
"there_are_superheroes": "NO"
}
]
}
]
},
{
"name": "dragon ball",
"answer": [
{
"there_are_superheroes": "YES",
"new_leaft": [
{
"name": "goku",
"answer": [
{
"there_are_superheroes": "YES",
"new_leaft": [
{
"name": "gohan",
"answer": [
{
"there_are_superheroes": "YES"
}
]
}
]
}
]
}
]
}
]
}
]
I tried something like this:
format(d) {
if (d.children) {
d.children.forEach((d) => {
format;
});
}
}
format(data);
I don't know how to get the structure I want. I have tried to do it with foreach, but at one point I don't know how to dynamically access until the last children, this is an example but I can have n levels where there can be elements with more children. In my real project I am getting a structure from a web service, I need to structure it like this.
the attribute called superheroes I want it to be shown inside an array called answer and inside of it, there_are_superheroes it will have its value.
"name": "MARVEL",
"answer": [
{
"there_are_superheroes": "YES", --> `there_are_superheroes` was `superheroes`,
"new_leaft": [
{
.
.
and new_leaft is the equivalent of children
As I said, I know how to go through objects and arrays but in this case, I don't know how to go to the last children nested of each object.
This is how to do one level of recursion:
function format(l){
const result = {name: l.name};
result.answer = [{there_are_superheroes: l.superheroes}];
result.answer[0].new_leaft = l.children;
return result;
}
format({
"name": "Big Bang Theroy",
"superheroes": "NO",
"children": [
{
"name": "Sheldon",
"superheroes": "NO"
}
]
})
// result:
{
"name": "Big Bang Theroy",
"answer": [
{
"there_are_superheroes": "NO",
"new_leaft": [
{
"name": "Sheldon",
"superheroes": "NO"
}
]
}
]
}
If the list of possible keys is fixed, it's very simple. Otherwise use Object.assign to copy all the keys (or just iterate through those), then modify the necessary keys.
Now you have to figure out where to put the recursion calls (hint: l.children.map(format), whether the key should be named tree or new_leaf(t), check if the field exists and handle accordingly, (See the question In Javascript. how can I tell if a field exists inside an object? - Stack Overflow), etc.

Filtering subarray of objects

I need to filter a subarray of elements.
var university = {
"fax": "123345",
"email": "test#test.com",
"url": "www.test.com",
"classes": [
{
"number": "1",
"name": "maths",
"students": [
{
"name": "Max",
"exams": [
{
"date": "2016-01-04T18:32:43.000Z",
"passed": false
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": true
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": false
},
{
"date": "2016-01-04T18:32:43.000Z",
"passed": true
}
]
},
{...}
]
},
{...}
]
}
Ok I need to get all the classes without filtering, all the students of each class without filtering, but in the exams array I only need to get the ones that passed.
I tried the following:
university.classes.students.exams.filter(function (el) {
return el.passed
});
But it is not working...
I've googled a solution to this without success...any help would be appreciated.
classes and students are arrays - so you have to loop those as well:
university.classes.forEach(function(uniClass) {
uniClass.students.forEach(function(student) {
student.exams = student.exams.filter(function (el) {
return el.passed;
});
});
});

Categories