How to ensure uniqueness in a collection of embedded document - node.js

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.

Related

Modified model in node.js not reflecting on MongoDB

I just modified my model Order for my API because I need a value to pass a condition. But unfortunately, my new set of properties (orderStatus) on my collection did not reflect on my MongoDB database.
I don't need to input a value for the property (orderStatus) since I set a default value ("Pending"). I tried to delete the entire collection orders to see any changes but there were none. Is there something else I need to do on my MongoDB or any command on the git?
Here is my code for my model
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
userId: {
type: String,
required: [true, "User ID is required!"]
},
products: [
{
productId: {
type: String,
required: [true, "Product ID is required!"]
},
quantity: {
type: Number,
required: [true, "Quantity is required!"],
min: 1,
default: 1
},
subtotal: {
type: Number,
required: [true, "Subtotal is required"],
default: 0
}
}
],
totalAmount: {
type: Number,
required: [true, "Total Amount is required!"],
default: 0
},
orderStatus: {
type: String,
required: [true, "Order Status is required!"],
default:"Pending"
},
purchasedOn: {
type: Date,
default: new Date
}
});
module.exports = mongoose.model("Order", orderSchema);
and a screenshot of my database
I will really appreciate your help! Thank you so much!
Your documents which were already created will not reflect your new schema field. Since those fields only will get reflected on the update only. So, add orderStatus as pending as the default. You must migrate those documents by the update method. This is going to be a one-time process.
So, in the terminal, you can write the following code and run
db.collection.update({}, {$set: {orderStatus: "Pending"}}, {upsert: true, muti: true})
Or you are comfortable with the code itself you can write your update code in your project itself like this
await orderModel.updateMany({}, {$set: {orderStatus: "Pending"}}, {upsert: true})
and make an API and call this code.
In this process, you will see that in your documents that new key called orderStatus with pending value has been created.

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.

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!

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

Mongodb & Mongoose not creating unique index

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 });

Resources