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
Related
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.
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.
I have an email field, where I want unique emails. I also want to have the possiblity of an empty field. I don't want it to check uniqueness if the email is empty/null/not present.
Here is my List schema defined in Keystone:
Book.add({
number: { type: Types.Number },
email: { type: Types.Email, initial: true, index: true, unique: true },
token: { type: Types.Text },
title: { type: Types.Text, initial: true },
author: { type: Types.Text, initial: true },
name: { type: Types.Text, initial: true },
dedication: { type: Types.Textarea, initial: true },
image: { type: Types.CloudinaryImage }
});
Keystone exposes the mongoose schema, so I can access that. I could add a custom validation which makes a query except if field empty, but I'm hoping for something more elegant.
I already have plenty of data, I don't know if that makes the indexing stuff more complex.
I assume from the fact that you're asking this question that unique: true is not doing what you want when the email field is left empty.
You could try setting sparse: true as shown here, if keystone simply passes that straight to the schema you should be fine.
If not, the best way, as you mention, is probably just to add a simple pre-save hook to do this for you, as there are currently no options in keystone to allow you to do this.
Hope that helps (and let me know if sparse: true works)!
Use Books.schema.index({email: 1}, {sparse: true}) after you add the field and remove the index: true from the field. This calls Mongoose directly.
Don't forget to remove the old index from your collection (or simply drop the table).
What I don't understand is why it wouldn't just work, because the options seem to be passed to Mongoose directly: https://github.com/keystonejs/keystone/blob/94b34fe2239a0b571bf1421d45493d32896502a9/fields/types/Type.js#L242
Perhaps it already worked and you had the old unique index on there?
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.
I have a User (document) in which I maintain a collection of Friends (embedded document). I've been trying to make sure that for a given user, all its friends are unique (email must be unique). However that constraint isn't enforce and I can't understand why. Anybody could please help me with that?
I am using Mongo 2.2 and Mongoose.
var FriendSchema = new mongoose.Schema({
email : { type: String, required: true, lowercase: true, trim: true }
, name : { type: String, trim: true }
});
var UserSchema = new mongoose.Schema({
email : { type: String, required: true, index: { unique: true }, lowercase: true, trim: true }
, friends : [FriendSchema]
});
UserSchema.index({ 'friend.email': 1 }, { unique: true });
Unique indexes means that no other documents are inserted with the same value specified in the index, this doesn't apply to embedded documents. If you tried to add foo#example.com to users A and B, it should fail due to the unique index.
You would have to enforce this in Node.JS rather than trying to do it with an unique index.