Filter documents using multiple fields - node.js

I have a collection named Project. Below is the schema description for Project collection :
const projectSchema = new mongoose.Schema(
{
projectName: {
type: String,
trim: true
},
licenceType: {
type: String,
trim: true,
lowercase: true
},
location: {
type: String,
lowercase: true,
trim: true
},
description: {
type: String,
trim: true
},
projectType: {
type: String,
default: 'public'
},
status: {
type: String,
default: 'open'
},
budget: {
type: Number
},
duration: {
type: Number
},
},
{
timestamps: true
}
);
I want to fetch documents using these fields as filters. The fields are :
licenceType
location
date (timestamp is made true in schema for this purpose)
I can use these three fields in any combination to fetch documents. There is a possibility that no filter is applied at all in which case its a simple fetching of all the documents in the collection.
I know I can dynamically build query using if--else if--else but I wanted to know is there any other more efficient way of handling such queries rather than using if--else blocks. If there would have been five or more fields for filtering purpose, there would be so many combinations to check using if--else block.
Appreciate any kind of help!!Thank You.

So, I assume there's some external trigger which actually modifies the filter matrix (eg. a request from some UI). Mongoose allows you to specify filter up-front in a form of an object, take a look below:
const query = Project.find({
licenceType: 'sometype',
location: 'somelocation'
});
Clearly you can see this...
{
licenceType: 'sometype',
location: 'somelocation'
}
...is an object. So, I think you could re-build the filtering object each time filters change (create an empty object let myFilters = {} and extend it with your filters: myFilters['licenceType'] = 'sometype') and pass myFilters to find function.

Related

Mongoose aggregate and append

I have a Mongo DB (latest version) that I am accessing with Mongoose (v6.5.4)
The project is using a discriminator pattern to keep all documents in the same collection.
There are many instances where i need to join documents.
Set up:
// Models:
const UserSchema = new Schema<IUser>(
{
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
});
// There are other similar models to <Team>
const TeamSchema = new Schema<ITeam>(
{
name: {
type: String,
required: true,
},
userIds: {
type: [Schema.Types.ObjectId],
required: true,
ref: "User",
default: [],
},
});
Problem:
I can use populate to return collections of Teams and the userIds be an array of user objects.
Where I am stuck is querying getting an array of users with an added field of teams[].
I've been trying aggregate to no success, I can loop over the users collection and return a list of Teams but this feels wrong and expensive in terms of read units (production data base is on a pay as you go service)
As data models go there is not much going for it - but it is an existing solution
Can anyone advise?
I was being stupid. The from field in my look up was wrong.
Should have been 'teams' not 'Team' which is the model name.

Allowing fields to be nulled in MongoDB schemas

I currently have an DB that has optional parameter fields in the schema JSON objects. At the moment, when the fields are UPDATED from an existing value(whether that be string, date, or otherwise) to null, upon retrieving the object the field is not actually nulled. How do I modify these schema fields to allow certain fields (say, the last three) in the object to be nulled upon an update, and displayed as such upon a subsequent GET request? I've tried making the type an array and adding null, but that clearly is not correct. Ive also tried default: null but that also did not work.
data: {
// Mandatory params
name: { type: String, required: true, index: true },
id: { type: String, required: true },
type: { type: String, required: true },
// Optional params
parent: { type: db.objectId(), ref: 'organisation' }
parentSpid: { type: String },
memberStatus: { type: String },
memberTier: { type: String },
memberExpiry: { type: Date }
}
I assume you are using Mongoose to wrap mongo? Under the hood, your queries will be using the $set operator which explicitly does not overwrite fields without a new value.
You should use the $unset operator to nullify fields.
For example, if you wished to nullify parent you would do:
Model.findOneAndUpdate({ ...QUERY }, { $unset: { parent: 1 } });
The $unset object can contain any fields you wish to nullify. Be wary that validators don't always run on updates in Mongoose. See https://mongoosejs.com/docs/validation.html

Nested Collection in MongoDB

const onboarderSchema = new Schema({
name: {
type: String,
required: [true, "name field is required"]
},
email: {
type: String
},
project: {
type: Object,
projectName: {
type: String,
required: [true]
},
projectDescription: {
type: String
},
manager: {
type: String,
required: [true]
},
mentor: {
type: String,
required: [true]
},
technologies: {
type: [Number],
required: [true]
}
}
});
This is a schema for my project which I am working on. The Project which is an object will have different projects added to it dynamically. So should I change the type of project to an array or something else? Cannot figure out what to do. Please suggest.
Make it array. Remember object is for a single information with fixed fields and values. on the other hand, array is to hold many information where you can put objects as many as you need dynamically. Then it will be called an array of objects. Keep the object fields same in the array to keep consistency and flexible query operation.
If you want to have multiple project inside your database the project field should be an array like
project:[{projectName:"p1"},
{projectName:"p2"},
{projectName:"p3"}]
or like this
project:["p1","p2","p3"]

Mongoose - How to prevent mongoose from creating _id on model instantiation

I want MongoDB itself to add an _id upon insertion so I can track the insertion time using the ObjectID but when I do new MyModel(...), moongose will add the id field.
How do I prevent this so the db itself adds the id?
Alternatively how do I create a field which will be set to the INSERTION time by the db?
Edit: I see that this is not technically possible with mongoose, so would it be possible to add a field that is set by MongoDB when the insertion is done?
My model (if relevant):
{
timestamp: {
type: Date,
required: true
},
signaler: {
type: String,
required: true,
trim: true
},
source: {
type: String,
required: false,
trim: true
},
category: {
type: String,
required: false,
trim: true
},
key: {
type: String,
required: true,
trim: true
},
level: {
type: String,
required: false,
trim: true,
uppercase: true,
enum: ['ALARM', 'WARNING', 'NORMAL']
},
payload: {
type: Schema.Types.Mixed,
required: true
}
}
It's an interesting use case you have. Mongoose really does create that _id on when you call a Model constructor!
I see three paths forward:
Don't use mongoose. The lower level mongo driver doesn't create _ids util you insert into a collection.
Pass around a plain javascript object until you are ready to save
it, then use the Model.create method.
Finally, you can use the pre save middleware to update the _id, by manually generating a new one (with mongoose.Types.ObjectId()) that will have more accurate time info.
If you want to introduce a createdAt field that is updated when the document is inserted, then you are also going handle the pre save middleware. That's the way this popular plugin does it: https://github.com/drudge/mongoose-timestamp/blob/master/index.js

Mongoose does not create text index

I have the following schema:
entrySchema = new mongoose.Schema({
size: { type: Number },
title: {type: String, trim: true },
content: { type: String, trim: true },
tags: { type: [String], trim: true, index: true },
author: { type: String, trim: true, index: true }
});
entrySchema.index({ title: "text", content: "text" });
module.exports = mongoose.model('Entry', entrySchema);
The problem is that mongoose does not create the text indexes. The indexes for tags and author are created correctly, though.
Am I using the index() function in a wrong way?
I don't get any errors in the mongod session. It logs successful index creation for the non-text indexes, but it seems as if mongoose never calls ensureIndex for the text indexes.
After debugging as described in Mongoose Not Creating Indexes (thanks to #JohnyHK for the link) I saw that the actual problem was not the text index.
I was using the mongoose-auto-increment plugin and that resulted in errors indexing the _id field.
The solution was to have autoIncrement not use the _id field but a separate field like this:
entrySchema.plugin autoIncrement.plugin, {
model: 'Entry'
startAt: 1000
field: 'shortId'
}
I just did not thing about that because indexing worked fine without the text index. There seems to be some kind of incompatibility with the plugin and text indexes.

Resources