Mongodb & Mongoose not creating unique index - node.js

I've searched the internet extensively, and no one seems to have an answer for this problem. I have a Mongoose Schema tied to a DB in Mongo. I want to create a unique index on the email field of my User document. The code below should work, as far as I can tell from the limited documentation I could find. Can anyone tell me why it fails, and allows me to create users with duplicate emails?
var userSchema = new Schema({
email: { type: String, required: true, index: { unique: true, trim: true } },
password: String,
firstName: String,
lastName: String
}, { autoIndex: true });

That trim probably shouldn't be there: it's a setting for strings, not for indexes. Try the following:
var userSchema = new Schema({
email: {
type: String,
trim: true,
required: true,
unique: true
},
password: String,
firstName: String,
lastName: String
}, { autoIndex: true });

Related

How to use virtual on a nested field in mongoose

I am using mongoose in node.js. I have the following Schema.
const CustomerSchema = new mongoose.Schema({
...
email: {
type: String,
required: true,
lowercase: true,
trim: true
},
addresses: [
{
addressType: {
type: String,
enum: [ 'personal', 'shipping', 'billing' ]
},
street: {
type: String,
required: true,
trim: true
},
streetNumber: {
type: String,
trim: true
},
floor: {
type: String,
trim: true
},
apartament: {
type: String,
trim: true
},
cp: {
type: String,
required: true,
trim: true
},
district: {
type: String,
trim: true
},
city: {
type: mongoose.Schema.ObjectId,
ref: 'City',
required: true
}
}
]
});
I want to use "virtuals" to "add" a new field in every object in the array addresses?
How I can do this using virtuals? Is it possible?
I can achieve the same result using, but I would like to use virtuals.
const customerDB = await Customer.findById(idCustomer).lean()
customerDB.addresses = customerDB.addresses.map((address) => ({
...address,
addressDesc: mapTypeAddressDescription(address.addressType)
}));
Many Thanks!
As the name suggests virtuals are not added to the MongoDB documents. They are used for computed properties on documents.
Suppose you have a User model. Every user has an email, but you also want the email's domain. For example, the domain portion of 'test#gmail.com' is 'gmail.com'.
Below is one way to implement the domain property using a virtual. You define virtuals on a schema using the Schema#virtual() function.
const userSchema = mongoose.Schema({
email: String
});
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
return this.email.slice(this.email.indexOf('#') + 1);
});
const User = mongoose.model('User', userSchema);
let doc = await User.create({ email: 'test#gmail.com' });
// `domain` is now a property on User documents.
doc.domain; // 'gmail.com'
You should check the documentation for more details.
You can do something like this:
CustomerSchema.path('addresses').schema.virtual('fullAddr').get(function() {
return 'foo'
})
Also, it is useful to check this answer on stackoverflow if the above one doesn't work.

How to add a new field to mongodb collection and make it unique?

I have a mongodb collections with several existing data, and now I want to add new field to the same collection at the same time the new field needs to be a unique field.
I'm using nodejs with mongoose.
Following is my current schema.
const user = new mongoose.Schema({
username: { type: string, required: true},
token: { type: String, required: true }
});
And now below is my new schema
const user = new mongoose.Schema({
username: { type: string, required: true},
token: { type: String, required: true },
nickname: { type: String, required: true }
});
user.index({ "nickname": 1}, { "unique": true });
Since it has existing data when I run the code it gives me below error.
E11000 duplicate key error collection: ourcompany.users index: nickname_1 dup key: { : null }
I believe when new field is creating it will be filed with null values. Since the new field is unique it is not allowing multiple null values.
I have scene this document but I can't understand what steps to follow.
Please enlighten me about the gap I need to fill.
Thanks in advance
use sparse: true So Make it as
const user = new mongoose.Schema({
username: { type: string, required: true},
token: { type: String, required: true },
nickname: { type: String, required: true,sparse: true }
});
Hope it helps!

Dont know how to populate Mongoose Query

I have a problem with a mongoose population and I don't know what I should do.
I got two schemas:
var userSchema = new userSchema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
mods: [{ type: mongoose.Schema.Types.ObjectId, ref: 'users'}]
});
var dataSchema = mongoose.Schema({
title: { type: String, required: true, unique: true },
description: { type: String, required: true },
owner: {type: mongoose.Schema.Types.ObjectId, required: true}
});
So one user can have several data packages.
Some users are moderated by other users.
Whats the query for a moderator, that all his own data packages and the ones of the users he is moderating are listed?
You see that I have a SQL background and there's definitely another way to do it with MongoDB.
Thanks for your help!
I'm not clear understand what queries do you need but first you need set ref property in 'owner' field in dataSchema. As about population it's look like this:
//if you use callback
users.find({/*your query*/}).populate('mods')
.exec((err, result)=>{/*your code*/});
//if you use promise
users.find({/*your query*/}).populate('mods').exec()
.then(result=>{/*your code*/})
.catch(err=>{throw err});

Tinder like application MongoDB database schema

I am developing an app like Tinder to experiment with MongoDB.
I am wondering about the database schema.
The main idea is that a user can "like" many users but no matter how much the number of "liked" profiles grows, it is very unlikely to hit the 16MB document size ceiling, so in my design, "liked" profiles are embedded inside one's profile.
below is a sample of my users schema using mongoose
var UserSchema = mongoose.Schema({
fullName: {
type: String,
trim: true
},
phone: {
type: String,
trim: true,
required: true,
},
gender: {
type: String,
enum: ['male', 'female'],
},
age: {
type: Number,
required: true
},
favorites: []
});
On the other hand, a user might be "disliked" by my many users.
So a user should not see on his next profile search the profiles of users who "disliked" him, so in my design I created a collection that holds the ID of the user who "disliked" and the ID of the user being "disliked".
below is a sample of my blocked schema using mongoose
var BlockedSchema = mongoose.Schema({
BlockerUserId: {
type: String,
required: true
},
BlockedUserId: {
type: String,
required: true
}
});
Do you think this is a good approach? and which indexes needs to be created?
Best,
You can manage dislike in the user collection only, you don't need a new collection.
var UserSchema = mongoose.Schema({
fullName: {
type: String,
trim: true
},
phone: {
type: String,
trim: true,
required: true,
},
gender: {
type: String,
enum: ['male', 'female'],
},
age: {
type: Number,
required: true
},
favorites: [],
dislike[]
});
and search like
var current_user_id = userdata._id;
db.users.find({dislike:{$ne:current_user_id}})
The above code is not syntactically correct but it will give you an idea.

Add uppercase: true to mongoose embedded document

If I have two schemas, one which will be embedded in the other:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Will embed this in the personSchema below
var addressSchema = new Schema({
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
});
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressSchema
});
module.exports = mongoose.model("Person", personSchema);
I can't seem to get the uppercase: true to work for embedded documents - no error is thrown, but it simply doesn't uppercase the state property. Or any kind of option like that.
I've been searching the Mongoose docs, but maybe I'm just not finding where it mentions that settings these kinds of additional options on subDocuments won't work.
Up until recently, Mongoose would throw an exception if you tried to directly embed one schema within another like you're doing. It looks like it's partially supported now, but apparently not for cases like this.
You can get this to work by using just the definition object from addressSchema instead of the schema itself in the definition of the address field of personSchema.
var addressObject = {
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
};
var addressSchema = new Schema(addressObject);
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressObject
});
Not positive if this is the best way to do it or not, but I added a pre-save hook (per the suggestion of #nbro in the comments) and that seems to be working:
var addressSchema = new Schema({
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
});
addressSchema.pre("save", function (next) {
this.state = this.state.toUpperCase();
next();
});
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressSchema
});
Update #1:
I seem to be able to find lots of cases of people embedding simple schemas without any additional validation (required: true) or alteration (uppercase: true) occurring. While the above solution does work, it seems kind of unnecessary. What I should probably be doing is just putting in the object literal to embed the info:
var personSchema = new Schema({
...
address: {
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
}
});
It seems like the only good reason to use a separate Schema is if you absolutely need the embedded data to have an _id attribute and you don't need to add additional validation or alteration options to any of the properties. If you need an _id, I'm guessing you should probably not be embedding the data, but saving it as a separate object and making a reference.
I'll keep updating this as I discover new information and best practices.
Update #2:
If you want to include validation to the embedded document, such as making the address property required, you're going to have to do it separately, as outlined in this very good blog post about it.

Resources