Mongoose WHERE OR LIKE syntax on referenced schemas - node.js

I have the following 2 schemas (Clinic and User):
const ClinicSchema = new Schema({
name: {
type: String,
unique: true,
required: true
},
createdBy: {
type: Schema.Types.ObjectId,
ref: 'user'
},
createdAt: Date,
updatedBy: {
type: Schema.Types.ObjectId,
ref: 'user'
},
updatedAt: Date
});
And Here is the user Schema
const UserModelSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
roles: {
type: [String],
required: true,
}
});
I want to write a query that will search a string that is contained in the clinic name OR createdBy(user) name OR createdBy(user) last name, and return all the clinics where either the clinic name matches part of the search string OR the created by name matches part of the search string OR the created by last name matches part of the search string here is the pseudo SQL alternative of what I am trying to explain:
SELECT * FROM clinics
JOIN users on clinics.createdBy = users.id
WHERE clinics.name LIKE '%STRING%'
OR users.firstname LIKE '%STRING%'
OR users.lastname LIKE '%STRING%'
I have been searching for this solution for the past 2 days and can't seem to be able to figure it out, more specifically I am trying to add the WHERE OR functionality to the following query:
const clinicsQuery = Clinic.find({
name: new RegExp(req.query.searchTerm, 'i')
});
....
const clinicsList = await clinicsQuery
.limit(limit)
.skip(skip)
.populate('createdBy', ['firstName', 'lastName']);

It can be performed with a $lookup
const clinicsQuery = Clinic.aggregate([{
$lookup:
{
from: 'user',
localField: 'createdBy',
foreignField: '_id',
as: 'user'
}},
{ $unwind: "$user"}
{
$match: {
$or: [
{"user.firstname": new RegExp(req.query.searchTerm, 'i')},
{"user.lastname": new RegExp(req.query.searchTerm, 'i')},
{ name: new RegExp(req.query.searchTerm, 'i')}
]
}
},
{$limit: limit}
]);
User will be in "user" field in the result. But you won't have a mongoose ready object :/

Related

How to sort nested populated field in MongoDB (Mongoose)?

I am trying to sort populated array based on the nested and populated field using mongoose but it is not working.
Here are my modals.
const campaignSchema = new Schema(
{
name: { type: String, required: true },
prospects: [{ type: mongoose.Types.ObjectId, ref: "Prospect" }],
}
);
const prospectSchema = new Schema(
{
strategy: { type: String, trim: true },
contact: { type: mongoose.Types.ObjectId, ref: "Contact", required: true },
primaryCaller: { type: mongoose.Types.ObjectId, ref: "Contact" },
}
);
const contactSchema = new Schema(
{
firstName: { type: String, required: true },
lastName: { type: String, required: true },
}
);
Now I am trying to populate prospects and contact in each prospect in and sort them by contact.firstName using the following code.
const campaign = await Campaign.findOne({ _id: id }).populate({
path: "prospects",
populate: [
{ path: "contact", select: "firstName lastName" },
{ path: "primaryCaller", select: "firstName lastName" },
],
options: {
sort: "contact.firstName",
},
}).lean();
I tested it with sort: "strategy", and it is working fine with it.
I also tried Aggregations but it also didn't help.

How to search in multiple collections in MongoDB using Mongoose

I have two collections User and UserType :-
var User = new mongoose.Schema({
username: {
type: String,
required: true,
},
userType: {
type: ObjectId,
ref: "UserType",
required: true,
},
});
var UserTypeSchema = new mongoose.Schema(
{
type: String,
type_code: Number,
type_description: String,
},
{ timestamps: true }
);
I want to search user based on username and typecode which is in UserType Collection.
I tried this code: -
User.findOne({
username: mobileNumber,
userType: { type_code: userTypeCode },
})
.populate("userType");
please correct this query.
you must to filter out populate results, with match option
In your case answer would be::
User.findOne({
username: mobileNumber,
}).populate({
path: "userType",
match: { type_code: userTypeCode },
});
you can check the documentation

Mongoose – querying subdocuments referenced by ID

I have 2 schemas connected like this:
const Brand = new mongoose.Schema({
_id: { type: String, required: true },
name: {
type: String,
required: true,
},
products: [{
type: String,
ref: 'Product',
}],
});
const Product = new mongoose.Schema({
_id: { type: String, required: true },
name: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
});
I want to find brands that have certain types of products, so I wrote a query (not including async/await and promises in the code below for simplicity)
const docs = Brand.find({ 'products.type': 'my-type-here' })
.populate([
{
path: 'products',
},
])
.sort({ index: 1 })
.exec();
This gives me 0 results, yet I know that there are brand with the type of products. What am I doing wrong here? Is it connected with the fact, that products are only referenced by their ids when I invoke find method?

How to name a foreign key different from db name in mongoose

Is there a way in mongoose + Node.js/Express to define the relation between the foreign key field and what I refer to that field in the model is? My issue is that I have a mongo database where my foreign keys are all formatted like 'exampleId' instead of 'example'. I could just call out 'exampleId' directly but then it leads to weird things like when I populate 'exampleId' instead of 'example' (which is confusing because once populated, it is now the 'example' itself instead of its id).
Here is how I do it now and it works with my graphQL server, but only if my field in the database is 'course' while my database's field is 'courseId'
const CourseSchema = new Schema({
_id: { type: String },
sections: [{
type: Schema.Types.String,
ref: 'Section'
}],
});
const SectionType = new GraphQLObjectType({
name: 'SectionType',
fields: () => ({
id: { type: GraphQLID },
courseId: {
type: require('./course_type'),
resolve(parentValue) {
return Section.findById(parentValue)
.populate('course')
.then(section => section.course);
}
},
}),
});
I figured it out! With the newest version of mongoose, you actually can use virtual fields to accomplish what I wanted to do and this technique allows for flexibility in laying out your schema. Say that my MongoDB collections look like the following:
Courses { _id, sectionIds }
Lectures { _id, courseId }
I can use the following schema in mongoose and it will allow me to refer to course.lectures or lecture.course instead of the usual course.lectureIds or section.courseId:
const CourseSchema = new Schema({
_id: { type: String },
});
CourseSchema.virtual('sections', {
type: Schema.Types.String,
ref: 'Section',
localField: 'sectionIds',
foreignField: '_id',
justOne: false,
});
CourseSchema.statics.findSections = function(id) {
return this.findById(id)
.populate('sections')
.then(course => course.sections);
}
const SectionSchema = new Schema({
_id: { type: String },
});
SectionSchema.virtual('course', {
type: Schema.Types.String,
ref: 'Course',
localField: 'courseId',
foreignField: '_id',
justOne: true,
});
Actually MongoDB isn't a relational database. You can alter the field and its name whatever you like. Ex I Have an Owner(Meteor.users) table and Patient Table with this column
ownerid : {type: String, min: 1},
firstname: {type: String, min: 1},
lastname: {type: String, min: 1},
middlename: {type: String, min: 1, optional: true},
createdbyid: { type: String },
createdbyname: { type: String },
createdat: { type: Date, defaultValue: new Date() },
updatedbyid: { type: String, optional: true },
updatedbyname : { type: String, optional: true },
updatedat: { type: Date, defaultValue: new Date() },
I can easily stamp the value of my {Meteor.Users()._id} to ownerid of my designated patient by just processing them at meteor.methods. You don't have to worry about foreign keys mongo doesn't do relational databases you can customize your database whatever you like. I Hope this helps ;)
Mongoose Documentation posits that _id has to be used in refs and that[i]t is important to match the type of _id to the type of ref. , e.g.:
var personSchema = Schema({
_id : Number, //it is `Number`
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }] // use `Number` to match
});
I also wonder if by 'database' you mean 'collection'.

How to better structure mongoose schemas with relationships

At the moment i have 4 models. User, profile, interests and tokens. Between user and profile there is a one to one relationship. Between User and tokens there is a one to many relationship. Between profile and interests there is also a one to many relationships, interests will be pre defined with the ability for an admin to add more later.
User
var UserSchema = new Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
phone: [{countrycode: String}, {number: String}],
tokens: [{type: Schema.Types.ObjectId, ref: 'Token'}],
profile: {
type: Schema.Types.ObjectId, ref: 'Profile'
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Profile
var ProfileSchema = new Schema({
username: {
type: String,
unique: true,
},
firstname: {
type: String
},
lastname: {
type: String
},
gender: {
type: String
},
dob: {
type: Date
},
country: {
type: String
},
city: {
type: String
},
avatar: {
type: String
},
about: {
type: String
},
interests: [{
type: Schema.Types.ObjectId,
ref: 'Interest'
}],
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Token
var TokenSchema = new Schema({
name: {
type: String,
},
value: {
type: String,
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Interests
var InterestSchema = new Schema({
name: {
type: String,
unique: true,
},
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
Have i set up these schemeas/relationships properly? Now if i wanted to give roles to a user would i create a new role schema?
thanks.
I think you need Relational database if you want to make relation in NoSQL db
You can't add relations in NoSQL. Only thing you can is to use schema as type of field in another schema, like
var Comments = new Schema({
title: String,
body: String,
date: Date
});
var BlogPost = new Schema({
author: ObjectId,
title: String,
body: String,
date: Date,
comments: [Comments],
meta: {
votes : Number,
favs : Number
}
});
mongoose.model('BlogPost', BlogPost);
Embedded Documents

Resources