How to implement nesting of a model itself - Mongodb & Sails - node.js

So far I've got it figured out with these 3 models:
User model
module.exports = {
schema: true,
attributes: {
// Relations
maps: {
collection: 'Map'
},
}
};
Map model
module.exports = {
schema: true,
attributes: {
// Relations
owner: {
model: 'User'
},
spots: {
collection: 'Spot',
via: 'map'
},
}
};
Spot model
module.exports = {
schema: true,
attributes: {
// Relations
map: {
model: 'Map'
},
parentSpot: {
model: 'Spot'
},
subSpotss: {
collection: 'Spot',
via: 'parentSpot'
},
}
};
So, if I query a Map, by user, I will get, i.e. this:
{
"owner": "1",
"id": "1",
"spots": [
{
"map": "1",
"title": "Test Spot",
"content_text": "asdasdasdasdasd",
"createdAt": "2015-07-14T15:39:50.066Z",
"updatedAt": "2015-07-14T15:39:50.066Z",
"id": "1"
},
{
"map": "1",
"title": "Another Spot",
"content_text": "hue hue hue hue hue",
"createdAt": "2015-07-14T15:40:17.313Z",
"updatedAt": "2015-07-14T15:40:17.313Z",
"id": "2"
}
],
"createdAt": "2015-07-14T15:38:32.571Z",
"updatedAt": "2015-07-14T15:38:32.571Z"
}
What I want, additionally, is to nest other spots inside spots, so I have a result like this:
{
"owner": "1",
"id": "1",
"spots": [
{
"map": "1",
"title": "Test Spot",
"content_text": "asdasdasdasdasd",
"spots": [
{
"map": "1",
"title": "Nested Spot",
"content_text": "dfgsdsfasdf",
"spots": [
{
"map": "1",
"title": "Another Nested Spot",
"content_text": "sometesxtisdjfiasj",
"spots": [
{
// more nested levels here
},
{
// more nested levels here
},
],
"createdAt": "2015-07-14T15:39:50.066Z",
"updatedAt": "2015-07-14T15:39:50.066Z",
"id": "5"
},
{
// more nested levels here
},
],
"createdAt": "2015-07-14T15:39:50.066Z",
"updatedAt": "2015-07-14T15:39:50.066Z",
"id": "3"
},
{
// another nested Spot which can have a collections of
// more Nested spots
},
{
// one more nested Spot which can have a collections of
// more Nested spots
}
],
"createdAt": "2015-07-14T15:39:50.066Z",
"updatedAt": "2015-07-14T15:39:50.066Z",
"id": "1"
},
So, basically, inside a single Map I want to have multiple "starting" Spots, which can have nested levels inside of them. I was searching for something, but could only find Tree-related examples, which go only left and right, and I want to have more than 2 options.
How can I write that in the Sails model? And is this feasible at all? A suggestion of better design is welcome.

Your model is right. It's because sails currently don't support populate at nested model. You can override default query by doing like in this solution.

Related

How to update some collection with different query parameters and with different set values?

I have an array of mongoDB collection -
[
{
"_id": "630499244683ed43d56edd06",
"userId": "630499234683ed43d56edd05",
"isPaid": "true"
},
{
"_id": "6304c19bda84477b41b4bbfa",
"userId": "630499234683ed43d56edd05",
"isPaid": "true"
},
{
"_id": "6304c1b5da84477b41b4bbfb",
"userId": "630499234683ed43d56edd05",
"isPaid": "true"
},
{
"_id": "6304c1cbda84477b41b4bbfc",
"userId": "630499234683ed43d56edd05",
"isPaid": "true"
},
]
I just want to add the order property to all the object but for all the specific _id I need to add the different order value
Like this -
[
{
"_id": "630499244683ed43d56edd06",
"userId": "630499234683ed43d56edd05",
"isPaid": "true",
"order": 7
},
{
"_id": "6304c19bda84477b41b4bbfa",
"userId": "630499234683ed43d56edd05",
"isPaid": "true",
"order": 5
},
{
"_id": "6304c1b5da84477b41b4bbfb",
"userId": "630499234683ed43d56edd05",
"isPaid": "true",
"order": 0,
},
{
"_id": "6304c1cbda84477b41b4bbfc",
"userId": "630499234683ed43d56edd05",
"isPaid": "true",
"order": 2
},
]
Please let me know How do I implement this approach in mongoDB?
I'm not using mongoose in my project.
You have to add the structure of the coming data, how it grouped with _id and the count of order. If it is an array of object, you can use loop. I don't think there is a solution to update different values in only one code.
If you want specific ids to have specific order values you need to update them separately. You could use bulkWrite with the updateOne method.
db.collection.bulkWrite( [
{ updateOne: {
filter: { _id: ... },
update: { $set: { order: 1 } }
} },
...
] )
Refer to the MongoDB documentation and to your language driver in particular: https://www.mongodb.com/docs/v6.0/reference/method/db.collection.bulkWrite/#updateone-and-updatemany

How to find data based on sub-field name in MongoDB using Mongoose?

There is a sub-field called 'name' in MongoDB Collection (User):
[
{
"teacher": {
"name": "Alex",
"email": "alex#domain.com"
},
"waiter": {
"name": "Feliks",
"email": "feliks#domain.com"
},
"pilot": [
{
"name": "Sam",
"email": "sam#domain.com"
},
{
"name": "alice",
"email": "alice#domain.com"
}
],
},
{
"teacher": {
"name": "max",
"email": "max#domain.com"
},
"waiter": {
"name": "Sam",
"email": "sam#domain.com"
},
"pilot": [
{
"name": "richard",
"email": "richard#domain.com"
},
{
"name": "alice",
"email": "alice#domain.com"
}
],
}
]
How can I find data based on the field 'name'. For example, when I'm looking for 'Sam', it should return me the all documents since 'Sam' is in "waiter" and "pilot" in first and second documents respectively.
I cannot do something like:
User.find({"teacher.name": "Sam", "waiter.name": "Sam", "pilot.name": "Sam" })
This will return me nothing as it is an AND logic. What I need is an OR logic.
You can use the $or operator.
So the query should look like this:
User.find({ $or: [
{ "teacher.name": "Sam" },
{ "waiter.name": "Sam" },
{ "pilot.name": "Sam" }
]
});
Read here for me details.

I need to push into nested array in node mongoose

I used node mongoose.
I need to update this array push new item into Breackfast(mealList.foodList.breackfast || any),
I want to add new foodlist by time can you please give me suggestion for how to do,
{
"_id": "5fe43eb44cd6820963c98c32",
"name": "Monday Diet",
"userID": "5f225d7458b48d0fe897662e",
"day": "Monday",
"type": "private",
"mealList": [
{
"_id": "5fe43eb44cd6820963c98c33",
"time": "Breakfast",
"foodList": [
{
"_id": "5fe43eb44cd6820963c98c34",
"foodName": "Eggs",
"Qty": "2",
"calories": "calories",
"category": "category"
}
]
},
{
"_id": "5fe43eb44cd6820963c98c36",
"time": "Lunch",
"foodList": [
{
"_id": "5fe43eb44cd6820963c98c37",
"foodName": "food1",
"Qty": "100g"
},
]
}
],
"createdAt": "2020-12-24T07:09:40.141Z",
"updatedAt": "2020-12-24T07:09:40.141Z",
"__v": 0
}
I tried:
Diet.updateOne(
{ "Diet.mealList._id": req.body.mealId },
// { $push: { "Diet.0.mealList.$.foodList": req.body.foodList } },
{ $push: { foodList: req.body.foodList } }
)
Few Fixes:
convert your string _id to object type using mongoose.Types.ObjectId
remove Diet from first and push object in foodList
Diet.updateOne({
"mealList._id": mongoose.Types.ObjectId(req.body.mealId)
},
{
$push: {
"mealList.$.foodList": req.body.foodList
}
})
Playground

Mongoose: Update of array inside another nested array element not working as expected

Here is my mongo schema:
{
"_id": ObjectId("5f8af2fc5f23667adf3bbaf2"),
"score": 2.5,
"questions": [{
"_id": ObjectId("5f8af30d5f23667adf3bbaf5"),
"desc": "some text",
},
{
"_id": ObjectId("5f8af3115f23667adf3bbaf8"),
"desc": "some text",
"options": [{
"_id": ObjectId("5f8af3115f23667adf3bbaf9"),
"name": "some name",
"desc": "description 1"
},
{
"_id": ObjectId("5f8af3115f23667adf3bbafa"),
"name": "some name",
"desc": "description 2"
}
]
}
]
}
I've to update the name and desc of the option having id as 5f8af3115f23667adf3bbaf9 which is in the one of the array elements of the question attribute having id as 5f8af30d5f23667adf3bbaf5 which is again part of the data having id as 5f8af2fc5f23667adf3bbaf2
Tried the following query which is getting executed successfully but not updating the option:
Model.findOneAndUpdate({
_id : ObjectId("5f8af2fc5f23667adf3bbaf2"),
"questions._id": ObjectId("5f8af30d5f23667adf3bbaf5"),
"questions.options._id": ObjectId("5f8af3115f23667adf3bbaf9"),
}, {
$set: {
"questions.$[q].options.$[o].order": data.order,
"questions.$[q].options.$[o].definition": data.definition,
"questions.$[q].options.$[o].type": data.type,
},
},
{
arrayFilters: [{ "q._id": ObjectId(qid) }, { "o._id": ObjectId(oid) }]
})
Is tihs possible to do in a single mongoose findOneAndUpdate method?
Your query is correct, I have just hardcoded object id values in array filter and it is updating the documents. I have updated name and desc as u said. Do try this out. One more thing in mongoose u have to specify the object id as "mongoose.Types.ObjectId".
Therefore in your case it would be like "q._id": mongoose.Types.ObjectId("5f8af3115f23667adf3bbaf8").
And one more thing is that you are using findAndUpdate, try using update only depending on your mongoose version
Here is mongoplayground:
https://mongoplayground.net/p/TP5iCTAC5R_
Query:
db.collection.update({
_id: ObjectId("5f8af2fc5f23667adf3bbaf2"),
"questions._id": ObjectId("5f8af3115f23667adf3bbaf8"),
"questions.options._id": ObjectId("5f8af3115f23667adf3bbaf9")
},
{
$set: {
"questions.$[q].options.$[o].name": "anotherName",
"questions.$[q].options.$[o].desc": "anotherDesc"
}
},
{
arrayFilters: [
{
"q._id": ObjectId("5f8af3115f23667adf3bbaf8")
},
{
"o._id": ObjectId("5f8af3115f23667adf3bbaf9")
}
]
})
Output :
[
{
"_id": ObjectId("5f8af2fc5f23667adf3bbaf2"),
"questions": [
{
"_id": ObjectId("5f8af30d5f23667adf3bbaf5"),
"desc": "some text"
},
{
"_id": ObjectId("5f8af3115f23667adf3bbaf8"),
"desc": "some text",
"options": [
{
"_id": ObjectId("5f8af3115f23667adf3bbaf9"),
"desc": "anotherDesc",
"name": "anotherName"
},
{
"_id": ObjectId("5f8af3115f23667adf3bbafa"),
"desc": "description 2",
"name": "some name"
}
]
}
],
"score": 2.5
}
]

Flter mongodb database using mongoose nodejs

I need to filter some users according to some fixed criteria. I have a user collection and a talent collection. The talent collection holds the reference to a master category collection.
What I need is to filter these users according to the category in the talent collection and some keys from the user collection.
For example I need to search for a user whose gender is 'male' and education 'BTech' and will have talents as a programmer and tester
my user collection is like,
{
"_id": "5f1939239bd35429ac9cd78f",
"isOtpVerified": "false",
"role": "user",
"adminApproved": 1,
"status": 0,
"languages": "Malayalam, Tamil, Telugu, Kannada",
"name": "Test user",
"email": "test#email.com",
"phone": "1234567890",
"otp": "480623",
"uid": 100015,
"bio": "Short description from user",
"dob": "1951-09-07T00:00:00.000Z",
"gender": "Male",
"education": "Btech",
"bodyType": "",
"complexion": "",
"height": "",
"weight": "",
"requests": [],
"location": {
"place": "place",
"state": "state",
"country": "country"
},
"image": {
"avatar": "5f1939239bd35429ac9cd78f_avatar.jpeg",
"fullsize": "5f1939239bd35429ac9cd78f_fullsize.png",
"head_shot": "5f1939239bd35429ac9cd78f_head_shot.jpeg",
"left_profile": "5f1939239bd35429ac9cd78f_left_profile.png",
"right_profile": "5f1939239bd35429ac9cd78f_right_profile.png"
},
"__v": 42,
"createdAt": "2020-07-23T07:15:47.387Z",
"updatedAt": "2020-08-18T18:54:22.272Z",
}
Talent collection
[
{
"_id": "5f38efef179aca47a0089667",
"userId": "5f1939239bd35429ac9cd78f",
"level": "5",
"chars": {
"type": "Fresher",
},
"category": "5f19357b50bcf9158c6be572",
"media": [],
"createdAt": "2020-08-16T08:35:59.692Z",
"updatedAt": "2020-08-16T08:35:59.692Z",
"__v": 0
},
{
"_id": "5f3b7e6f7e322948ace30a2c",
"userId": "5f1939239bd35429ac9cd78f",
"level": "3",
"chars": {
"type": "Fresher",
},
"category": "5f19359250bcf9158c6be573",
"media": [
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c22573065f84a48e04a14",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_undefined.jpeg",
"description": "test",
"fileType": "image",
"caption": "test file"
},
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c2d7a8c7f8336b0bfced2",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_1.jpeg",
"description": "this is a demo poster for testing",
"fileType": "image",
"caption": "A Test Poster"
}
],
"createdAt": "2020-08-18T07:08:31.532Z",
"updatedAt": "2020-08-18T19:35:22.899Z",
"__v": 2
}
]
And the category in the above document is a separate one populated to this. the category collection as,
[
{
"_id": "5f19359250bcf9158c6be573",
"status": true,
"title": "Testing",
"description": "Application tester",
"code": "test",
"characteristics": [],
"createdAt": "2020-07-23T07:00:34.221Z",
"updatedAt": "2020-07-23T07:00:34.221Z",
"__v": 0
},
{
"status": true,
"_id": "5f29829a705b4e648c28bc88",
"title": "Designer",
"description": "UI UX Designer",
"code": "uiux",
"createdAt": "2020-08-04T15:45:30.125Z",
"updatedAt": "2020-08-04T15:45:30.125Z",
"__v": 0
},
{
"_id": "5f19357b50bcf9158c6be572",
"status": true,
"title": "programming",
"description": "Java programmer",
"code": "program",
"createdAt": "2020-07-23T07:00:11.137Z",
"updatedAt": "2020-07-23T07:00:11.137Z",
"__v": 0
}
]
So my filter terms will be;
{
categories: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"],
minAge: 18,
maxAge: 25,
minHeight: 5,
maxHeight: 6,
minWeight: 50,
maxWeight: 80,
complexion: "white",
gender: "male",
}
And the expected result will be a user have both the above talents and followed conditions,
{
users: { ..User details.. },
medias: { ...medias from the matching talents.. }
}
If there are two collections you need to join them either by primary key or _id with foriegn fields and you can use $lookup with $match to filter down.
Documentation
You need to use $lookup with pipeline,
$match you condition for category match
$lookup to join users collection
$match conditions for users collections fields
$match exclude documents that don't found matching users of criteria passed in conditions
db.talents.aggregate([
{
$match: {
category: { $in: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"] }
}
},
{
$lookup: {
from: "users",
as: "users",
let: { userId: "$userId" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$$userId", "$_id"] },
{ $eq: ["$gender", "Male"] },
{ $eq: ["$education", "Btech"] }
// ... add you other match criteria here
]
}
}
}
]
}
},
{ $match: { users: { $ne: [] } } }
])
Playground

Resources