I have this model and I want to do a sort where the requests are sorted in this order(estadoPedido:Pendente,estadoPedido:Agendado,EstadoPedido:Concluido)
Is that possible?
var requestSchema = new Schema({
paciente: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: [true, "paciente is a required field"],
},
encaminhado: {
type: Boolean,
required: [true, "encaminhado is a required field"],
}, //vem do body
pessoaRisco: {
type: Boolean,
required: [true, "pessoaRisco is a required field"],
}, //vem do body
trabalhoRisco: {
type: Boolean,
required: [true, "trabalhoRisco is a required field"],
}, //vem do body
estadoPedido: {
type: String,
enum: ["Pendente", "Agendado", "ConcluĂdo", "Aguarda Resultado"],
},
resultado: { type: String, enum: ["Positivo", "Negativo"] },
dataExame: {
type: Date,
},
prioridade: { type: Number },
});
Although there are solutions suggested here on Stack Overflow.
But the solutions as of now is to use aggregation pipeline, this approach can't be optimised with an index and requires a full collection scan to transform every document.
I would like to suggest an alternative workaround that might work well specifically for mongoose. But it does require data migration, but if you are still in early development, this is possible.
What you can do is modify your schema for estadoPedido:
estadoPedido: {
type: String,
enum: ["1_Pendente", "2_Agendado", "3_ConcluĂdo", "4_Aguarda", "5_Resultado"] // or use any other sortable prefix and separator symbol
index: true,
get(estadoPedido) {
const [, value] = estadoPedido.split('_') // this assumes you don't originally have _ in your enum
// or put your own logic to get your original value back
return value
}
}
Then when you want to query, you can just do
Request.find().sort({ estadoPedido: 1 })
mongoose will execute the get function and transform estadoPedido to original value on every document.
Warning
Keep in mind that this with this solution, you'll get the original value only in a mongoose document, when you use it somewhere else, e.g. in an aggregation, you will have to use the prefixed value
Related
I am new to MangoDB and Node JS. I have always worked on SQL databases and I do not know the syntax of MongoDB well. I wanna try to filter the array that I receive from a MongoDB database. I know that JavaScript has a .filter() function to filter just the results that contain a string. Is it best practice to get all the objects from MongoDB and filter in Node or do I let MongoDB do the filtering?
My Node.JS project is a back-end project using Node.JS and Express to do CRUD operations on a MongoDB database. In the request I send a parameter called 'equalTo' that contains the value that should be filtered on.
var router = express.Router();
var Plot = require("./models/plot");
...
router.get("/plots", (req, res) => {
let query = "" + req.query.equalTo;
Plot.find((err, plots) => {
if (err) {
res.send(err);
}
res.json(plots);
});
});
The filtering should be an OR filter where all results where either the name or the cropName should CONTAIN the value of the string. If it is possible I would also like the comparison to ignore uppercase's. Here is a schema for the Plot object:
const plotSchema = mongoose.Schema({
area: {
type: String,
required: true
},
comments: {
type: String,
required: true
},
cropGroupName: {
type: String,
required: true
},
cropName: {
type: String,
required: true
},
name: {
type: String,
required: true
},
plotId: {
type: Number,
required: true
},
coords: {
type: [],
required: true
},
}, {
collection: "plots"
});
The format is the following:
Plot.find({$or:[{name: "anyname"},{cropName:"othername"}]})
For further information you can read here https://docs.mongodb.com/manual/reference/operator/query/or/
You may replace the strings above in your case with equalTo.
I've a mongodb collection which stores "Customers" data. I need to trim the mobile number of a customer if there are any trailing or leading white spaces available. I've used trim() function to remove them. But am getting an error, trim() is not a function.
Here's my model schema:
var schema = mongoose.Schema({
name : {type: String, required: true},
email : {type: String, required: true},
mobile : {type: String, required: true, index: false, unique: false});
module.exports = mongoose.model("customer", schema);
Here's the code where I've used trim function:
addNewCustomer: async function(payload){
var customer = new Customer({
name : payload.name,
email : payload.email,
mobile: payload.mobile.trim()
});
}
When I execute the above function, it is giving me the error.
But if I use trim() at schema level, it is working fine.
mobile : {type: String, required: true, index: false, unique: false, trim: true});
What is the difference between using trim() in SCHEMA level and FUNCTIONALITY level? Why it is not working when used in function?
Have seen functional alternative 'cursor' syntax ala:
db.collection.find({},{ "category": 1 }).forEach(function(doc) {
db.collection.update(
{ "_id": doc._id },
{ "$set": { "category": doc.category.trim() } }
);
})
Above example copied from: https://stackoverflow.com/a/46554968/2003321
I have a few models which I need to work with. However, the model won't be added as a document in a collection unless there is a unique attribute in the schema. This happens in my localhost mongo and in mongo atlas.
Every model with a property who has a unique constraint gets added the normal way. Every model without will not be added.
When the code is written as this everything works fine:
const UserSchema = new Schema ({
firstName: {
type: String,
required: [true, "firstName is required"]
},
lastName: {
type: String,
required: [true, "lastName is required"]
},
email: {
type: String,
required: [true, "email is required"],
index: { unique: true }
},
password: {
type: String,
required: [true, "password is required"]
},
appartments: [{
type: Schema.Types.ObjectId,
ref: "appartments"
}],
})
When the email index property gets commented out, the document will not appear:
email: {
type: String,
required: [true, "email is required"]
//index: { unique: true }
},
I want to add the model as a document without setting a unique constraint in every model.
So I'm back and figured it out!
Apparently, a model does not get added as a document until you create it from code. Because the user schema already has an index added from code it gets created. So to make your model visible as a collection you need to do something like this:
Apartment.create({title: "My Apartment"})
.then(apartment => {
console.log("The apartment model is now visible with entry: " + apartment);
}).catch((error) => next(new ApiError(error, 400)))
I am trying to create an event list where users can add and remove themselves from events and specify if they are bringing guests with them to that event.
So I have an event schema and a user schema, where the event schema is referencing the user schema. So when a new event is created users can add themselves to that event with their ids.
Now I'm trying to make it so that users can also include guests. How Do I achieve that?
Here's an example
User Schema:
let UserSchema = new mongoose.Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
name:{
type: String,
require: true
},
password: {
type: String,
required: true
},
...
Event Schema:
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
// Guest property is ignored
attending: [{
type: mongoose.Schema.Types.ObjectId,
guest: Number, //This is being ingored and never updated
ref: 'User'
}]
})
Second way of defining the relavant part in the schema:
...
//In this example the guest will be added but duplicates will occur
user:[{
guest: Number, // To make it clear this is not referencing anything it's just a number
attending: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}]
How do I update the type and guest properties with addToSet (to prevent duplication) in the above configuration?
Event.findOneAndUpdate({_id:req.body.eventId}, query)
I don't think you understand how mongoose schemas work, you might want to spend some more time on their documentation.
What you have provided as code is what appears to be a field called Events in your Schema which is an array of objects, each object of which has a single field called attending, which itself is required to be an ObjectId type and reference the 'User' collection. There is also a guest property on the field definition which will be ignored by Mongoose as it doesn't understand what you're asking for.
Realize that what this data structure is, is instructions to Mongoose on how to validate and persist your data. It won't generally be updated at runtime for most applications and will not store data directly, again its purpose is to give clues to Mongoose as to how you want the data stored.
/** Edit based on comments and updated question **/
As I said before, you can't directly embed another field into the definition of a field. What you can do is create a mixed type which has both pieces of information, but that will require you to manage things yourself to some degree.
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
attendees: [{
user : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
guests : Number
}]
})
Anytime anyone is added to the attending list, you'll need to call event.markModified() to make sure it gets saved. If you don't want to allow duplicate users, you'll also need to check that. One way to make sure that happens is to populate() that field when you fetch the event, then just check locally for matches.
/** Edit #2 **/
You can also explicitly create another schema to 'hold' your user and # guests information, which will then create models that Mongoose will watch, and you can apply validation to them via normal Mongoose methods and not worry about dirty checking. That'd look like this:
// in ./models/attendee.js
let AttendeeSchema = new Schema({
user : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
unique : true
},
guests : Number
}
mongoose.model('Attendee', AttendeeSchema);
// in your Events definition
let Attendee = mongoose.model('Attendee');
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
attendees: [Attendee]
})
/** Edit 3: Now, with queries **/
To insert a new attendee, given an existing event and a known user:
event.attendees.push(new Attendee({user: user, guests: 5}));
event.save(console.log);
To update an existing attendee, you'll need to find the one you're looking for first:
let attendee = event.attendees.find((attendee) => { return attendee._id.toString() === user._id.toString(); });
attendee.guests = 10;
event.save(console.log);
This is (a part) of my model:
var materialSchema = new Schema({
ownerType: { type: String, required: true},
organization: {
type: Schema.ObjectId,
ref: 'organization'
},
user: {
type: Schema.ObjectId,
ref: 'users'
},
});
I want to make a query that returns:
ownerType = 'public'
organization = 321
The condition are 'OR'. So the material should be either ownerType 'public' or organization 321.
Can not find this in the docs. Do I need to make nested queries with "find" to do this? Or can it be done with a single query?
Some pseudo code:
mongoose.model('material').find({ownerType:'public' || organization:321}, function(err,materials){
...
}
Well presuming that your actual "Model" is named Material then you would come out to something like this in MongoDB parlance:
Material.find(
{
"$or": [
{ "ownerType": "public" },
{ "orginization._id": 123 }
]
},
function(err,docs) {
// results in here
}
);
So MongoDB has an $or operator, which makes sense since the query operands are represented in BSON ( from JSON conversion in the JavaScript case ). The purpose presents an "array" of possible arguments which are evaluated in a "short circuit" manner to determine if either case results in a true condition to match your query criteria.