How to implement inner join in mongoose - mongodb

Problem:
I want to achieve an inner join in mongoose for a model which has dynamic ref and direct ref to another model(s). Pls refer to the sample schema and models below.
const schema1 = mongoose.schema({
on: {
type: Schema.Types.ObjectId,
required: true,
refPath: 'onModel'
},
onModel: {
type: String,
required: true,
enum: ['Model2', 'Model3']
},
company: {
type: Schema.Types.ObjectId,
ref: 'Company'
}
});
const Model1 = mongoose.model('Model1', schema1);
const schema2 = mongoose.schema({
name: {
type: String,
maxlength: 100
},
email: {
type: String,
maxlength: 100
}
});
const Model2 = mongoose.model('Model2', schema2);
const schema3 = mongoose.schema({
name: {
type: String,
maxlength: 100
},
email: {
type: String,
maxlength: 100
}
});
const Model3 = mongoose.model('Model3', schema3);
const companySchema = mongoose.schema({
companyName: {
type: String,
maxlength: 100
}
});
const company = mongoose.model('Company', companySchema);
const res = await models.Model1
.find()
.populate({
path: 'on',
match: {
'name': keyword
}
})
.populate({
path: 'company',
match: {
'companyName': keyword
}
});
The above find returns documents even if on and company returns null value (as mongoose populate implements left join by default).
Expected Result: I want to fetch documents from model1 only if it matches the keyword with name field in model2 or model3 or with company name field in company model.
How to achieve this? Your help is much appreciated.

1.Let's update the schema for "Model 1" like below:-
const schema1=mongoose.schema( {
ref: {
kind: String, // <-- This will store the Model Name (Model2 or Model3) when you execute the insert query.
item: {
type: mongoose.Schema.Types.ObjectId, // <-- This will store the Reference ID of another table (Model2 OR Model3)
refPath: 'ref.kind', fields: String,
}
,
}
, company: {
type: Schema.Types.ObjectId, ref: 'Company'
}
});
Keep the schema for Model2 , Model3 & Company as it is. No need to make any change here.
When you want to find :-
await models.Model1.find().populate({ path: 'ref.item' });
That's it. This should work.

Related

How to Find record by ObjectID's property in Mongodb?

Suppose I have 2 models like Orders and Customers.
const orders = mongoose.Schema({
customer_id: {
type: mongoose.Schema.ObjectId
required: true,
ref: 'Customer',
},
OrderNo: {
type: String,
required: true,
})
const customers = mongoose.Schema({
name: {
type: String,
required: true,
})
I want to filter orders based on customer's name as per below.
let query = {
'customer_id.name': { $regex: '.*AMAZON.*' },
}
await Orders.find(query)
but its not working properly. I'm new to mongodb. Can anyone share feasible solution ? Thanks
Try to populate and filter the resulting fields:
await Orders.find({})
.populate({ path: 'customer_id', match: { name: { $regex: '.*AMAZON.*' } } })
.exec();

How to get SQL's "AND" operator behavior in mongoose

const ItemSchema = new mongoose.Schema({
categoryId: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'Category'
},
companyId: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'Company'
},
name: {
type: String,
required: true
}
})
const CategorySchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
displayOrder: {
type: Number,
required: true,
},
description: {
type: String
}
});
const companySchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true
},
address: {
address: String,
city: String,
state: String,
country: {
type: mongoose.Schema.Types.ObjectId,
ref: 'countrycodes'
},
pincode: String,
}
});
I have this above schema and trying to get the items which has company name="KFC" and category name="food"
Along with the items I want to populate the company and category objects.
const itemList = await Item.find().populate(
{
path: 'companyId',
match: { name: 'KFC'},
select: '_id name'
}).populate(
{
path: 'categoryId',
match: { name: 'food'},
select: '_id name'
}
).lean();
I tried using populate as shown below but this returns items which do not have category name="food" but has comp
name="KFC"
How can I get the items which has company name="KFC" and category name="food" and ignore the ones which do not satisfy both company and category condition.
Also, Is populate() the right way to get the results I want?

Populate data using another collection in mongoose v6.2.8

Im having issues populating my mongoDB collection with another collection based off the _id. It Keeps returning an empty object with no errors or anything?
Property Schema
const PropertySchema = new Schema({
landlord: {
type: Schema.Types.ObjectId,
ref: "Landlord",
required: true,
},
...
});
Landlord Schema
import { Schema as _Schema, model } from "mongoose";
const Schema = _Schema;
const LandlordSchema = new Schema({
fname: {
type: String,
required: true,
},
lname: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
company: {
type: String,
},
});
const Landlord = (module.exports = model("Landlord", LandlordSchema));
export function get(callback, limit) {
Landlord.find(callback).limit(limit);
}
Property Controller
exports.readProperty = async (req, res) => {
await Property.find({ _id: req.params.propertyId })
.populate({
path: "Landlord",
select: "fname lname email phone company",
model: "Landlord",
strictPopulate: false,
})
.then(function (err, property) {
if (err) return res.send(err);
res.json(property);
});
};
mongodb Property Collection
Mongodb Landlord Collection
When running the get call from postman it returns:
I fixed this issue by selecting the field: landlord not Landlord

MongoDB Mongoose Scheme Nested Document Structure and Relations

I have a project with the following document flow.
Users -> Accounts -> Projects
Users
Users have specific roles
Accounts
CRUD conditioned by User role
Specific users will have access to individual accounts. I was thinking to add an array userGroup with user id's?
Projects
Nested under Accounts related to a single accountToken ID
CRUD conditioned by User role
Specific users will have access to individual projects.
Here are example Schema models simplified for demo purposes.
UserSchema.js:
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please add an email'],
unique: true,
},
role: {
type: String,
enum: ['admin', 'user'],
default: 'user'
}
});
module.exports = mongoose.model('User', UserSchema);
AccountSchema.js:
const AccountSchema = new mongoose.Schema({
accountName: {
type: String,
},
accountToken: {
type: String
}
});
module.exports = mongoose.model('Account', AccountSchema);
ProjectSchema.js:
const ProjectSchema = new mongoose.Schema({
projectName: {
type: String,
},
projectType: String,
projectToken: String
})
module.exports = mongoose.model('Project', ProjectSchema);
I am stuck on the best way to setup nested or sub-document Schema Relations and the best way to relate the data between each other. Any guidance and suggestions would be a huge help! Thanks!!!
Try this;
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please add an email'],
unique: true,
},
role: {
type: String,
enum: ['admin', 'user'],
default: 'user'
}
});
module.exports = mongoose.model('User', UserSchema);
const AccountSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
accountName: {
type: String,
},
accountToken: {
type: String
}
});
module.exports = mongoose.model('Account', AccountSchema);
const ProjectSchema = new mongoose.Schema({
accountTokenId:{
type: String
},
projectName: {
type: String,
},
projectType: String,
projectToken: String
})
module.exports = mongoose.model('Project', ProjectSchema);

How create nested mongoDb schema in mongoose?

i'm trying to design mongoose shema for users cleaner and customer, they have some common fields e.g. name, but also have extra (different fields) client(rating) and customer number. I'm not sure that my design is good.
I've created separate userSchema for customer and cleaner, and created separate address schema.
// User Schema
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
// AddressSchema
const AddressSchema = new mongoose.Schema({
city: {
type: String,
required: true
},
street: {
type: String,
required: true
}
});
// CustomerSchema
const CustomerSchema= new mongoose.Schema({
name: UserSchema,
address: AddressSchema
});
// CleanerSchema
const CleanerSchema= new mongoose.Schema({
name: UserSchema,
rating: {
type: Number,
required: true
}
});
My schema doesn't work. Could you give best practice example for my schema?
This is how I would define your Customer and Cleaner schemas. I don't think it's necessary to create the separate name and address schemas.
const CustomerSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
address: {
city: {
type: String,
required: true
},
street: {
type: String,
required: true
}
}
});
const CleanerSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
}
});