How to specify field which is array of objects, objects of array has one of attribute as unique but optional in Mongoose? - mongodb

This is my schema for employee personal information
const mongoose = require('mongoose');
const PersonalInformationSchema = mongoose.Schema({
name: {
type: String,
required: true
},
emails: [{
email: {
type: String,
trim: true,
unique: true
},
isPrimary: {
type: Boolean
}
}]
}, {
timestamps: true
});
module.exports = mongoose.model('PersonalInformation', PersonalInformationSchema);
In my case I have array emails which is optional for employee but should be unique. When I insert a record without emails, document saves successfully (with empty array emails: []) but in next try it says
"err": {
"driver": true,
"name": "MongoError",
"index": 0,
"code": 11000,
"errmsg": "E11000 duplicate key error collection: EmployeePersonalInformation.personalinformations index: emails.email_1 dup key: { : null }"
}

You can add sparse: true to your schema, try:
const PersonalInformationSchema = mongoose.Schema({
name: {
type: String,
required: true
},
emails: [{
email: {
type: String,
trim: true,
unique: true,
sparse: true
},
isPrimary: {
type: Boolean
}
}]
}, {
timestamps: true
});
The sparse property of an index ensures that the index only contain entries for documents that have the indexed field. The index skips documents that do not have the indexed field.
So when empty documents will be skipped you won't get an error from unique constraint.

Related

Uniques fields in MongoDB Atlas

I'm trying to make a field unique in MongoDB Atlas but I don't understand how to make it.
Here I have my data, that I post with an NodeJS API Rest. How can I make the field "ID" unique?
I know that MongoDB Atlas adds 2 fields more, _id and _ _v, but I need ID to be unique, so when I do a POST in the API, I avoid having repetead data.
I only added unique to Mongoose Schema
const mongoose = require('mongoose')
const userSchema = mongoose.Schema({
"id": {
type: Number,
required: true,
unique:true
},
"email": {
type: String,
required: true,
unique:true
},
"first_name":{
type: String,
required: true
},
"last_name":{
type: String,
required: true
},
"company":{
type: String,
required: true
},
"url":{
type: String,
required: true,
unique:true
},
"text":{
type: String,
required: true
}
});
module.exports = mongoose.model('User', userSchema);

Query in command must target single shard key

I have an array of document ids using which I wish to delete the documents with the given id. The document id is also the shard key of the document. So I provided the following query for model.deleteMany(query)
query:
{ doc_id: { '$in': [ 'docid1', 'docid2' ] } }
I still get the error Query in command must target single shard key.
Is it possible to overcome this without looping through the array and deleting the docs one by one?
By matching any document in the collection with the _id field, you can make a query or delete command:
db.collection.deleteMany({ _id: { $exists: true }})
During the specification of the schema model in the code, a Shard Key (Partition Key) must be specified. We may execute operations such as save, update, and delete once it is provided
const mySchema = new Schema({
requestId: { type: String, required: true },
data: String,
documents: [{ docId: String, name: String, attachedBy: String }],
updatedBy: {
type: {
name: { type: String, required: true },
email: { type: String, required: true },
}, required: true
},
createdDate: { type: Date, required: true },
updatedDate: { type: Date },
}, { shardKey: { requestId: 1 } }
);

MongoDB: Set and get Sub Document Schema

I'm using mongoose and I have users collection shown below, but I now want to allow the user to save a number of articles, an article has a title, subtitle, and body, One user can have many articles.
How can I restructure the users collection to allow the articles to be added
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
timestamps: true,
}
);
I'm using the below to set new data to the user's collection, how do I adapt it to allow me to set and get the new articles detailed above?
const confirmed = await userModel
.findOneAndUpdate(
{ email },
{
$set: { password },
}
)
.exec();
You can set the option strict: false and add(save) new fields to your schema.
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
strict: false,
timestamps: true,
}
);
Here is the docs

Data is not inserted as per schema

I had defined mongoose schema and i tried to insert data into mongodb.But it is not inserted as per defined schema
export const EmpSchema: mongoose.Schema = new Schema({
name: {
type: String,
required: true
},
empNo: {
type: String,
required: true
},
skill: {
type: [String],
required: true
},
address: {
type: String,
required: true
}
}, {
_id: false,
versionKey: false,
retainKeyOrder: true
});
It is getting stored like Array elements as last field.like
name
empno
address
skill
export const EmpSchema: mongoose.Schema = new Schema({
name: {
type: String,
required: true
},
empNo: {
type: String,
required: true
},
skill: {
type: [String],
required: true
},
address: {
type: String,
required: true
}
}, {
_id: false,
versionKey: false,
retainKeyOrder: true
});
YOUR SCHEMA DEFINATION IS CORRECT PLEASE CHECK THE CONTROLLER PART WHERE YOU PUT THE INSERT QUERY . THERE MATTERS A INSERTION ORDER

Mongoose document schema and validation

I Have a schema like so:
class Schemas
constructor: ->
#mongoose = require 'mongoose'
#schema = #mongoose.Schema
#EmployeeSchema = new #schema
'firstname': { type: String, required: true },
'lastname': { type: String, required: true },
'email': { type: String, required: true, index: { unique: true }, validate: /\b[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ },
'departmentId': { type: #schema.ObjectId, required: true }
'enddate': String,
'active': { type: Boolean, default: true }
#EmployeeSchemaModel = #mongoose.model 'employees', #EmployeeSchema
#DepartmentSchema = new #schema
'name': { type: String, required: true, index: { unique: true } }
'employees' : [ #EmployeeSchema ]
#DepartmentSchemaModel = #mongoose.model 'departments', #DepartmentSchema
So that my employees live in an array of employee documents inside a department
I have several department documents that have a number of employee documents stored in the employees array.
I then added a new department but it contained no employees. If I then attempt to add another department without employees, Mongoose produces a Duplicate key error for the employee.email field which is a required field. The employee.email field is required and unique, and it needs to be.
Is there anyway round this?
If you enable Mongoose debug logging with the coffeescript equivalent of mongoose.set('debug', true); you can see what's going on:
DEBUG: Mongoose: employees.ensureIndex({ email: 1 }) { safe: true, background: true, unique: true }
DEBUG: Mongoose: departments.ensureIndex({ name: 1 }) { safe: true, background: true, unique: true }
DEBUG: Mongoose: departments.ensureIndex({ 'employees.email': 1 }) { safe: true, background: true, unique: true }
By embedding the full EmployeeSchema in the employees array of DepartmentSchema (rather than just an ObjectId reference to it), you end up creating unique indexes on both employees.email and department.employees.email.
So when you create a new department without any employees you are 'using up' the undefined email case in the department.employees.email index as far a uniqueness. So when you try and do that a second time that unique value is already taken and you get the Duplicate key error.
The best fix for this is probably to change DepartmentSchema.employees to an array of ObjectId references to employees instead of full objects. Then the index stays in the employees collection where it belongs and you're not duplicating data and creating opportunities for inconsistencies.
Check out these references:
http://docs.mongodb.org/manual/core/indexes/#sparse-indexes
mongoDB/mongoose: unique if not null (specifically JohnnyHK's answer)
The short of it is that since Mongo 1.8, you can define what is called a sparse index, which only kicks in the unique check if the value is not null.
In your case, you would want:
#EmployeeSchema = new #schema
'firstname': { type: String, required: true },
'lastname': { type: String, required: true },
'email': { type: String, required: true, index: { unique: true, sparse: true }, validate: /\b[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ },
'departmentId': { type: #schema.ObjectId, required: true }
'enddate': String,
'active': { type: Boolean, default: true }
Notice the sparse: true added to your index on EmployeeSchema's email attribute.
https://gist.github.com/juanpaco/5124144
It appears that you can't create a unique index on an individual field of a sub-document. Although the db.collection.ensureIndex function in the Mongo shell appears to let you do that, it tests the sub-document as a whole for its uniqueness and not the individual field.
You can create an index on an individual field of a sub-document, you just can't make it unique.