I have an array contains object look like below
[
{
_id: "12",
data: { _id: "123", isDelete: false, name: "afd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
{
_id: "12",
data: { _id: "123", isDelete: false, name: "ffd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
]
This is when I filter in it
brands.filter(brand => {
console.log(brand);// like above data
console.log(brand.data);// show brand.data
console.log(brand.data._id);//error brand.data is not defined
})
I already try
brands.filter(brand => {
let a = brand.data;
console.log(a._id);// error a is null
})
I need to get brand.data.name like when I loop it need to print afd and ffd.
As per your question if all you want to do is to log the value of brand.data.name then using filter doesn't make any sense.
You can just use forEach for that.
const brands = [
{
_id: "12",
data: { _id: "123", isDelete: false, name: "afd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
{
_id: "12",
data: { _id: "123", isDelete: false, name: "ffd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
}
];
brands.forEach(brand => { console.log(brand.data.name) });
If you want to store the names in an array instead of just logging them then you can use map for that.
const brands = [
{
_id: "12",
data: { _id: "123", isDelete: false, name: "afd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
{
_id: "12",
data: { _id: "123", isDelete: false, name: "ffd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
}
];
const brandNames = brands.map(brand => brand.data.name);
console.log(brandNames);
Javascript filter works on array. So considering you want to filter your nested object(based on id) which is data, your code should be written like below-
const brands = [
{
_id: "12",
data: { _id: "1", isDelete: false, name: "afd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
{
_id: "13",
data: { _id: "2", isDelete: false, name: "ffd" },
createdAt: "2020-04-11T08:38:15.966Z",
shop_id: "sfd",
updatedAt: "2020-04-27T02:07:12.271Z"
},
]
const updatedBrands = brands.map(brand => {(
...brand, brand.data.filter(key => key._id === '1')
}))
You have to first use javascript map method to iterate over the array and then you can filter your data object by id. Hope this helps.
Related
This is my first post so please bear with me. I am building a LinkedIn clone and I am trying to keep track of the work experience, projects and courses of the users, and those will be kept in an array of objects inside of the User schema. Now let's say a user will try to add or update one of the elements in one of those arrays, I have the user ID and I am passing it to findOneAndUpdate() as the filter.
Here is my User schema:
const userSchema = new mongoose.Schema({
user_id: {
type: String,
required: [true, 'User ID required.'],
unique: true,
immutable: true,
},
name: {
type: String,
required: [true, 'Name required.'],
},
email: {
type: String,
required: [true, 'Email required.'],
unique: true,
lowercase: true,
immutable: true,
},
title: {
type: String,
},
location: {
type: String,
},
phone_number: {
type: String,
},
contact_email: {
type: String,
},
photo: {
type: String,
},
website: {
type: String,
},
backdrop: {
type: String,
},
summary: {
type: String,
},
work: {
type: String,
},
connections: {
type: Number,
},
projects: [
{
title: {
type: String,
},
description: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
technologies: {
type: String,
},
picture: {
type: String,
},
},
],
skills: [{
skill: {
name: {
type: String,
},
level: {
type: String,
},
},
}],
experience: [
{
company: {
type: String,
},
logo: {
type: String,
},
title: {
type: String,
},
location: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
},
logo: {
type: String,
},
degree: {
type: String,
},
location: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
languages: [
{
name: {
type: String,
},
level: {
type: String,
},
},
],
awards: [
{
title: {
type: String,
},
date: {
type: Date,
},
awarder: {
type: String,
},
summary: {
type: String,
},
},
],
courses: [
{
title: {
type: String,
},
number: {
type: String,
},
school: {
type: String,
},
start_date: {
type: Date,
},
end_date: {
type: Date,
},
description: {
type: String,
},
},
],
});
And in my UserController.ts file, I tried using this:
const updateUser = async (req: Request, res: Response) => {
try {
const filter = { user_id: req.body.user_id };
const update = req.body;
const updatedUser = await User.findOneAndUpdate(filter, update, {
new: true,
upsert: true,
});
res.status(201).json({
status: 'success',
data: {
user: updatedUser,
},
});
} catch (err) {
res.status(400).json({
status: `ERROR: ${err}`,
message: 'error updating user',
});
}
};
And in my request using the format of the schema but that didn't work out as expected. I know mongoose will automatically give it an _id field to each of the individual objects in the array, but again, I have had no luck updating them. I tried sending a PATCH request with this as the body to add a skill like so:
{
"user_id": "xxxxxxxxxxxxxxxx",
"title": "Mr.",
"skills" : {
"name": "Flute",
"level": "Novice"
}
}
And this was the response I got. It created a skill but didnt add the data in the skill object:
{
"status": "success",
"data": {
"user": {
"_id": "63d3715f2ef9698667230a53",
"user_id": "xxxxxxxxxxxxxxxx",
"name": "Jonathan Abitbol",
"email": "yoniabitbol1#gmail.com",
"projects": [],
"skills": [
{
"_id": "63d4068d2df30c9e943e4608"
}
],
"experience": [],
"education": [],
"languages": [],
"awards": [],
"courses": [],
"__v": 0,
"title": "Mr."
}
}
}
Any help on how to add/edit the nested objects would be appreciated.
I have a problem with a query that I can't solve 100%
The fact is that when a user does not have any comment within the post. As inside the comments there is a "createdBy" and I need to make a lookup of that user inside the array. If there are no comments, it returns an array with an empty object, but it must return an empty array, not with empty objects.
Who can help me? Thank you very much in advance!
HERE MY USER collection (data)
[
{
_id: ObjectId("619d0f5df3f74665aff1a551"),
name: "Test Name",
surname: "Test Surname2",
createdAt: ISODate("2021-11-11T17:21:58.624+01:00"),
updatedAt: ISODate("2021-11-25T10:35:25.842+01:00"),
posts: [
{
_id: ObjectId("619d0f5df3f74575aff1a551"),
updatedAt: ISODate("2021-11-23T16:57:17.816+01:00"),
createdAt: ISODate("2021-11-23T16:57:17.816+01:00"),
content: "Test content....",
comments: [
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfaaaa88266dc91b9489c"),
},
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfc60a88266dc91b95741"),
},
],
date: ISODate("2021-11-23T16:57:17.820+01:00"),
},
{
_id: ObjectId("619d0f5df3f74575aff1a551"),
updatedAt: ISODate("2021-11-23T16:57:17.816+01:00"),
createdAt: ISODate("2021-11-23T16:57:17.816+01:00"),
content: "Test content....",
comments: [],
date: ISODate("2021-11-23T16:57:17.820+01:00"),
},
],
},
{
_id: ObjectId("619d0f5df3f74665aff1a551"),
name: "Test Name",
surname: "test surname",
createdAt: ISODate("2021-11-11T17:21:58.624+01:00"),
updatedAt: ISODate("2021-11-25T10:35:25.842+01:00"),
posts: [
{
_id: ObjectId("619d0f5df3f74575aff1a551"),
updatedAt: ISODate("2021-11-23T16:57:17.816+01:00"),
createdAt: ISODate("2021-11-23T16:57:17.816+01:00"),
content: "Test content....",
comments: [
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfaaaa88266dc91b9489c"),
},
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfe7ba88266dc91b961b6"),
},
],
date: ISODate("2021-11-23T16:57:17.820+01:00"),
},
{
_id: ObjectId("619d0f5df3f74575aff1a551"),
updatedAt: ISODate("2021-11-23T16:57:17.816+01:00"),
createdAt: ISODate("2021-11-23T16:57:17.816+01:00"),
content: "Test content....",
comments: [
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfaaaa88266dc91b9489c"),
},
{
createdBy: ObjectId("618d4326f1668007b3b98404"),
comment: "test comment...",
_id: ObjectId("619dfc60a88266dc91b95741"),
},
],
date: ISODate("2021-11-23T16:57:17.820+01:00"),
},
],
},
];
HERE MY AGGREGATE QUERY
db.users.aggregate([
{ $unwind: { path: '$posts', preserveNullAndEmptyArrays: true } },
{ $unwind: { path: '$posts.comments', preserveNullAndEmptyArrays: true } },
{
$lookup: {
from: 'users',
localField: 'posts.comments.createdBy',
foreignField: '_id',
as: 'posts.comments.createdBy'
}
},
{ $unwind: { path: '$posts.comments.createdBy', preserveNullAndEmptyArrays: true } },
{
$group: {
_id: { _id: '$_id', post_id: '$posts._id' },
name: { $first: '$name' },
posts: { $push: '$posts' },
comments: { $push: '$posts.comments' },
}
},
{
$group: {
_id: '$_id._id',
name: { $first: '$name' },
posts: {
$push: {
_id: '$_id.post_id',
date: { $first: '$posts.date' },
content: { $first: '$posts.content' },
comments: '$comments'
}
}
}
},
])
Here an image with the fail array:
you have to remove preserveNullAndEmptyArrays field from unwind to don't have empity objects
I'm learning Mongo and I'm not understanding something about the aggregate function. I have a User that can make many different kinds of posts, I match the user by blogName and then $lookup all posts that have the matching user ID.
After that I'm stumped. If I unwind and don't group then I get the mess of joined documents, but all I want are the posts.
If I group after $unwind then the documents are turned back into objects.
This code:
return User
.aggregate([
{
$match: {
blogName: blogName
}
},
{
$lookup: {
from: 'posts',
localField: '_id',
foreignField: 'user',
as: 'posts'
}
},
{
$unwind: "$posts"
},
{
$group: {
_id: "$_id",
'posts': { $push: { fields: '$posts' } }
}
},
Gives me this:
[
{
_id: 6065e579bf709d81274cc51e,
posts: [ [Object], [Object], [Object], [Object] ]
}
]
Adding a second $unwind after $group just gives me this:
[
{ _id: 6065e579bf709d81274cc51e, posts: { fields: [Object] } },
{ _id: 6065e579bf709d81274cc51e, posts: { fields: [Object] } },
{ _id: 6065e579bf709d81274cc51e, posts: { fields: [Object] } },
{ _id: 6065e579bf709d81274cc51e, posts: { fields: [Object] } }
]
Which is further from what I want.
I just want the posts. If I can $unwind the posts in this array then I can handle everything from there. What am I not understanding about this?
Update 1:
If I just use $project like so:
return User
.aggregate([
{
$match: {
blogName: blogName
}
},
{
$lookup: {
from: 'posts',
localField: '_id',
foreignField: 'user',
as: 'posts'
}
},
{
$unwind: "$posts"
},
{
$project: {
"_id": 0,
"posts": "$posts"
}
},
I can get this array:
[
{
posts: {
_id: 60664856447970128fee597b,
descriptionImages: [],
tags: [],
likes: [],
kind: 'TextPost',
createdAt: 2021-04-01T22:25:26.531Z,
updatedAt: 2021-04-01T22:25:26.531Z,
title: '',
body: '',
user: 6065e579bf709d81274cc51e,
__v: 0
}
},
{
posts: {
_id: 60664925d2548912dc960e05,
mainImages: [],
descriptionImages: [],
tags: [],
likes: [],
kind: 'PhotoPost',
createdAt: 2021-04-01T22:28:53.179Z,
updatedAt: 2021-04-01T22:28:53.179Z,
user: 6065e579bf709d81274cc51e,
description: '',
__v: 0
}
},
{
posts: {
_id: 6066495f347bb812fd6dc703,
mainImages: [],
descriptionImages: [],
tags: [],
likes: [],
kind: 'PhotoPost',
createdAt: 2021-04-01T22:29:51.815Z,
updatedAt: 2021-04-01T22:29:51.815Z,
user: 6065e579bf709d81274cc51e,
description: '',
__v: 0
}
},
{
posts: {
_id: 60664961347bb812fd6dc704,
descriptionImages: [],
tags: [],
likes: [],
kind: 'TextPost',
createdAt: 2021-04-01T22:29:53.385Z,
updatedAt: 2021-04-01T22:29:53.385Z,
title: '',
body: '',
user: 6065e579bf709d81274cc51e,
__v: 0
}
}
]
But now I'm stumped as to how to get rid of the extra level of nesting. I just need each post object without the additional nesting under posts.
Demo - https://mongoplayground.net/p/bCwBJipyYYZ
db.collection.aggregate([
{ $match: { blogName: "abc" } },
{ $unwind: "$posts" },
{ $replaceRoot: { "newRoot": "$posts" } }
])
Use $replaceRoot
Replaces the input document with the specified document. The operation replaces all existing fields in the input document, including the _id field. You can promote an existing embedded document to the top level, or create a new document for promotion (see example).
User.aggregate([
{ $match: { blogName: blogName } },
{ $lookup: { from: 'posts', localField: '_id', foreignField: 'user', as: 'posts' } },
{ $unwind: "$posts" },
{ $replaceRoot: { "newRoot": "$posts" } }
]
I`ve modeled a document to be:
let UserSchema = new Schema({
name: { type: String, required: true, max: 50, unique: true },
email: {type: String, required: true, max: 50, unique: true},
password: {type: String, required: true, max: 20},
monitoringProject: [
{
projectName: { type: String, required: true, max: 30},
token: { type: String, required: true},
dispositives: [
{
name: { type: String, required: true, max: 15},
value: { type: String, required: true},
token: { type: String}
}
]
}
],
controlProject: [
{
projectName: { type: String, required: true, max: 30},
token: { type: String, required: true},
dispositives: [
{
name: { type: String, required: true, max: 15},
value: { type: String, required: true},
token: { type: String}
}
]
}
]
});
In the monitoringProject, for example, I can log too many different projects, and, to each project, I can log too many dispositives. So, I have nested arrays. In other project, where I have just one project, and many dispositives, I can list them and search for just one dispositive. But in this case, like this:
[ { "_id": "5ee18ece1ea5af75bae55f91", "monitoringProject": [ { "dispositives": [ { "_id": "5ee18ef31ea5af75bae55f9c", "name": "Dispositivo 1", "token": "$2b$15$NntmY9ihNZ7R1Vg1WMtmzOSjlfCoKIuHLofF6g5tKXA57WLLc2At2" }, { "_id": "5ee18ef81ea5af75bae55f9e", "name": "Dispositivo 2", "token": "$2b$15$OZB7HbDLvonsv6A71ozW7.yVY2vJOipTCj0AH7XzoafQwwDho.jpm" }, { "_id": "5ee18efc1ea5af75bae55fa0", "name": "Dispositivo 3", "token": "$2b$15$0hpDzNeTO2qJzBVyAHc/UesrnIRi/YpeAlpCLewNhmfl6fe3SEN0i" }, { "_id": "5ee2278d0754817853134bf3", "name": "Dispositivo 4", "token": "$2b$15$ldC5/CyxITPJGUvtXJ.2S.D6a3FBftg6ctQeS4ne/9xpMP5PPiszK" }, { "_id": "5ee2288956fc4c7870044395", "name": "Dispositivo 6", "token": "$2b$15$3rJt.gXEi/gALvrwxVUsWuwF2RUcBmZcoFOQeXwF45ZuKQrB3AGHG" }, { "_id": "5ee6d23d1756b7a8384bcff0", "name": "Dispositivo 7", "token": "$2b$15$C3I9STKJpf9i/7hzhvHEs.IizXpOEmgRTD3hd7ZSdcvATb73Z0zNC" } ], "_id": "5ee18ede1ea5af75bae55f94", "projectName": "Projeto 2", "token": "$2b$15$xaytMbMnGd3BMAGapX8nn.imvkQKetqx0OIlUUyP3gCxlKz/G6DiG" } ] } ]
I can only list all the Dispositives. I want to return just, for example, "Dispositivo 2".
I used to querys:
await User.find({ email: req.body.email, monitoringProject: { $elemMatch: { token: req.body.projecttoken, dispositives: { $elemMatch: { token: req.body.dispositivetoken } } } } }, { "monitoringProject.$.dispositives": 1} )
or
await User.find({ email: req.body.email, 'monitoringProject.token': req.body.projecttoken, 'monitoringProject.dispositives.token': req.body.dispositivetoken}, { 'monitoringProject.dispositives.$': 1 })
Using find or findOne. How can I return just the document I want? I tried so many different ways, but with no lucky.
I'm sending this JSON with Angular.js to my node.js/express.js service:
{
"name": "MyGuitar",
"type": "electric",
"userid": "123",
"likes": 0,
"dislike": 0,
"guitarParts": {
"body": {
"material": "/content/img/hout.jpg",
"_id": "5566d6af274e63cf4f790858",
"color": "#921d1d"
},
"head": {
},
"neck": {
"material": "/content/img/hout.jpg",
"_id": "556d9beed90b983527c684be",
"color": "#46921d"
},
"frets": {
},
"pickup": {
},
"bridge": {
},
"buttons": {
}
}
}
The guitarParts are not saved in the MongoDB database.
Mongoose inserts the following:
Mongoose: guitars.insert({ name: 'MyGuitar', type: 'electric', userid: '123', likes: 0, _id: ObjectId("557023af9b321b541d4d416e"), guitarParts: [], __v: 0})
This is my Mongoose model:
guitarPart = new Schema({
id: { type: String, required: true },
color: { type: String, required: true },
material: { type: String, required: true },
x: { type: Number, required: false },
y: { type: Number, required: false },
width: { type: Number, required: false },
height: { type: Number, required: false},
});
guitarParts = new Schema({
body: [guitarPart],
neck: [guitarPart],
head: [guitarPart],
bridge: [guitarPart],
frets: [guitarPart],
pickup: [guitarPart],
buttons: [guitarPart]
});
guitar = new Schema({
name: { type: String, required: true, unique: false },
type: { type: String, required: true },
userid: { type: String },
likes: { type: Number },
dislikes: { type: Number },
guitarParts: [guitarParts],
kidsguitar: { type: Boolean },
lefthanded: { type: Boolean },
assemblykit: { type: Boolean }
},
{
collection: 'guitars'
});
I don't know what's going wrong. Any ideas?
According to the mongoose documentation of Subdocuments says: Sub-documents are docs with schemas of their own which are elements of a parents document array
And in your schema you provided: guitarParts is not an array, it is an object and a guitarPart is not array it is an object too. So that's why it is not saving.
So the correct way to model your Schema it would be:
var guitarDefinition = {
_id: {type: String, required: true},
color: {type: String, required: true},
material: {type: String, required: true},
x: Number,
y: Number,
width: Number,
heigth: Number
};
var guitarSchema = Schema({
name: { type: String, required: true, unique: false },
type: { type: String, required: true },
userid: String,
likes: Number,
dislikes: Number ,
kidsguitar: Boolean,
lefthanded: Boolean ,
assemblykit: Boolean,
guitarParts: {
body: guitarDefinition,
neck: guitarDefinition,
head: guitarDefinition,
bridge: guitarDefinition,
frets: guitarDefinition,
pickup: guitarDefinition,
buttons: guitarDefinition
}
});
Actually I have run in my computer and it is saving you can see my complete code here: https://gist.github.com/wilsonbalderrama/f10c38f9fb510865edc2