Complex MongoDB Join Query - database

i want to get recipes of users that a specific user is following them
when target_user_id in following schema equal to user_id in recipe schema
Following Schema
user_id:{type:mongoose.ObjectId, require:true},
target_user_id:{type:mongoose.ObjectId, require:true}
Recipe Schema
user_id:{type:mongoose.Schema.ObjectId, require:true},
username:{type: String, require: true},
type: { type: String, require: true },
title: { type: String, require: true },
description: { type: String, require: false },
ingredients: { type: Array, require: true },
directions: { type: Array, require: true },
cook_note: { type: String, require: false },
reviews_score: { type: Array, require: false, default:[0,0,0,0,0]}

Solved
const {_id:user_id} = req.user
const recipes = await recipe_model.aggregate([
{ $lookup:{
from:'follows',
localField: "user_id",
foreignField: "target_user_id",
as: "followers"
}},
{ $match : {followers: {$elemMatch:{ user_id: { $eq: user_id } } }}}
])

Related

How do I update individual fields in nested objects that are in arrays in MongoDB using Mongoose?

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 am having difficulty accessing this nested array to carry out an update

SCHEMA
Below is my schema structure, kindly correct me if I am getting it wrong. I want to be able to update the ConnectState from false to true using an ObjectId
phones: {
type: String,
required: true,
},
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
// required: true,
},
Userpost: {
type: mongoose.Schema.Types.ObjectId,
ref: "userpost",
// required: true,
},
friendshipStatus: [
{
isFriend: {
FProfile: {
type: mongoose.Schema.Types.ObjectId,
ref: "profile",
},
ConnectStatus: {
type: Boolean,
default: false,
},
},
},
],
});
What I have tried
I want to update the Boolean value on ConnectStatus from false to true. I know I am getting the process wrong.
const result = await Profile.updateOne(
{ "friendshipStatus.isFriend.FProfile": uid },
{ $set: { "friendshipStatus.$.isFriend.ConnectStatus": true } },
{ arrayFilters: [{ "friendshipStatus.isFriend.FProfile": uid }] }
);
Try with:
const result = await Profile.update(
{ 'friendshipStatus.isFriend.FProfile': uid },
{ $set: { 'friendshipStatus.$.isFriend.ConnectStatus': true } },
);

Advanced search with mongoose

I have an query object
const query = {
brand : BMW,
yearFrom : 2000,
yearTo : 2003,
price : 7000,
};
I am trying to find every BMW which is made between 2000 and 2003 included.
I am trying in this way but it doesn't work
if (query.yearFrom) {
return offerModel.find({query,year : {$gte : query.yearFrom }}, function(err,arr) {console.log(err,arr)}).skip(offset).limit(12);
}
Here's the mongoose schema
const mongoose = require('mongoose');
const offerSchema = new mongoose.Schema({
brand: {
type: String,
required: true,
},
model: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
color: {
type: String,
required: true,
},
power: {
type: Number,
required: true,
},
mileage: {
type: Number,
required: true,
},
populatedState: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
condition : {
type: String,
required: true,
},
doors: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
},
transmission: {
type: String,
required: true,
},
engineType: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
imageURLs : [],
imageIds : [],
creator: {
type: mongoose.Types.ObjectId,
ref: 'user'
},
})
module.exports = mongoose.model('offers', offerSchema);
Sample data from database
_id:60fe98301b76642e04a31c45,
imageURLs:[],
imageIds : [],
brand:BMW,
model:335,
year:2000,
color:White,
doors:4,
power:130
mileage:30000,
populatedState:Sofia,
price:7000,
condition:Used,
description:qweqweqweqe,
transmission:Automatic gearbox,
engineType:Petrol,
category:Sedan,
creator:60fe97d11b76642e04a31c44,
__v:0,
If i put only query it find brand,model and etc.But it doesn't get year search correctly.
I will be glad if you guys have some ideas how can i fix that
Thanks !
Try this
offerModel.find({
$and: [
{ brand :query.brand },
year : {
$gte: query.yearTo,
$lt: query.yearFrom
}
]
}, function (err, results) {
...
}

Mongoose: Find() return document with the the object that contains the value

I'm using MongoDB, and express.
I have a collection with all the countries, contains the states and cities.
Picture of a part of the collection
Now,
lets say I want to get all the cities that contains "Los" (like "San Antonio", "San Diego"),
when I'm using Find() - its return the all document with all the states and all the cities in the country (like in the picture above),
I want to return the all documents, but return only the objects that contains the value, inside array "cities"
Note: I expect to get different countries with cities that contains a part of the value in their names.
how to use the Find() to return as I want ?
hers is the schema I'm using:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CitiesSchema = new Schema({
capital:{
type: String,
required: true
},
currency:{
type: String,
required: true
},
emoji: {
type: String,
required: true
},
emojiU: {
type: String,
required: true
},
id: {
type: Number,
required: true
},
iso2: {
type: String,
required: true
},
iso3: {
type: String,
required: true
},
name: {
type: String,
required: true
},
native: {
type: String,
required: true
},
phone_code: {
type: String,
required: true
},
region: {
type: String,
required: true
},
states:
[{
cities:[{
id:{
type: Number,
required: true
},
latitude:{
type: String,
required: true
},
longitude:{
type: String,
required: true
},
name:{
type: String,
required: true
},
}],
id:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
state_code:{
type: String,
required: true
},
}]
,
subregion: {
type: String,
required: true
}
});
const Cities = mongoose.model('Cities',CitiesSchema);
module.exports = Cities;
Edit: my Find() code:
Cities.find({"states.cities.name": city})
.then((data)=>{
return res.json(data);
})
lets say I want to search cities with the name "Los Santos". I want the result to be like this:
Picture of the result I expect to be return
instead, I'm getting the all states and cities in the countries - which I don't want.
UPDATE:
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})
Try using RegEx, I use it while doing searches on MongoDB.
Cities.find({"states.cities.name": new RegExp(city)})
.then((data)=>{
return res.json(data);
})
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})

Apollo GraphQl model attribute is not accessing object in ReactJs

I am implementing category and subcategory display in ReactJs using Apollo GraphQl Query.
I tried to using same table as category with fields.
id,
category_name,
category_img,
category_parent_id ( id from same table),
category_status,
typeDefs and resolver are belows
Category.js
const typeDefs = gql`
extend type Query {
getSingleCategory(id: ID): allCategory
}
`;
type allCategory {
id: ID!
category_name: String
category_img: String
category_parent_id: Int
category_status: Status
}
const resolvers = {
Query: {
getSingleCategory: async (parent, args, context, info) => {
var data = await db.category.findOne({
where: {
id: args.id,
},
include: [
{
model: db.category,
as: "children",
attributes: [["category_name", "children_name"]],
nested: true,
required: false,
},
],
required: false,
});
return data;
},
},
},
Model in GraphQl
module.exports = function (sequelize, DataTypes) {
var category = sequelize.define(
"category",
{
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
category_name: {
type: DataTypes.STRING(256),
allowNull: false,
},
category_img: {
type: DataTypes.STRING(256),
allowNull: false,
},
category_parent_id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
references: {
// WorkingDays hasMany Users n:n
model: "category",
key: "children",
},
},
category_status: {
type: DataTypes.ENUM("Acitve", "Inactive"),
allowNull: false,
},
},
{
tableName: "category",
timestamps: false,
}
);
category.associate = function (models) {
models.category.belongsTo(models.category, {
onDelete: "CASCADE",
foreignKey: "category_parent_id",
as: "children",
targetKey: "id",
});
};
return category;
};
In ReactJs
category.ts
export const GET_CATEGORYBY_ID = gql`
query($catId: ID!) {
getSingleCategory(id: $catId) {
id
category_name
category_img
category_parent_id
category_status
}
}
`;
I am trying to accessing {data.getSingleCategory} , I got all parameters but not able to get children_name from same table as parent_name.
Anyone can tell me what is the issue I am not able to access that children_name as attribute from same table Or there any other way so that we can access category/subcategory from same table and display it to reactjs template.
Not defined [separately] in types, not used/defined [as 'children' property?] in parent type, not requested in query ... simply filtered out from response.

Resources