Mongo Giving 'duplicate key error' on non-unique fields - angularjs

I am getting a MongoDB error when trying to insert a subdocument. The subdocs already have unique _ids, but an error is being thrown for a different, non-unique field that I don't want unique.
The error in Angular is: "Assets.serial already exist". How can I make this field contain duplicate values, and what is causing the model to assume it should be unique?
Here is my Mongoose model:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var AssetUrlSchema = new Schema({
name: {
type: String,
unique: false,
default: '',
trim: true
},
url: {
type: String,
unique: false,
default: 'http://placehold.it/75x75',
trim: true
},
}),
AssetSchema = new Schema({
serial: {
type: Number,
unique: false
},
urls: {
type: [AssetUrlSchema],
unique: false,
default: [
{ name: '', url: 'http://placehold.it/75x75' },
{ name: '', url: 'http://placehold.it/75x75' }
]
}
}),
/**
* Item Schema
*/
ItemSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please enter name',
trim: true
},
assets: {
type: [AssetSchema],
default: [],
unique: false
},
property: {
type: Schema.ObjectId,
zd: 'Please select a property',
ref: 'Property'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Item', ItemSchema);
And here is my 'save' method:
function(){
var i = 0, assets = [];
for (;i < 24;i++) {
assets.push({
serial: 1000+i,
urls: {
name: 'Asset Name ' + i,
url: 'http://placehold.it/75x75?'
}
});
}
item = new Items ({
name: 'FPO',
property: newPropId,
assets: assets
});
return item.$save(
function(response){ return response; },
function(errorResponse) {
$scope.error = errorResponse.data.message;
}
);
}
The first time I insert a document, it works fine. Any subsequent time, it fails with a 400 because the assets.serial field is not unique. However, I am specifically marking that field as unique:false.
The error in the mode console is:
{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }]
name: 'MongoError',
code: 11000,
err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }' }
POST /api/items 400 14.347 ms - 41

Mongoose doesn't remove existing indexes so you'll need to explicitly drop the index to get rid of it. In the shell:
> db.items.dropIndex('assets.serial_1')
This will happen if you initially define that field unique: true but then later remove that from the schema definition or change it to unique: false.

If you're using MongoAtlas, you can go to the collection -> click 'indexes' -> on the index you want to delete, click 'drop index'

If you are in a dev/prototype mode, simply deleting the actual collection (after changing the unique:true to false for instance), will reset everything and mongoose will allow your duplicates.

Related

How can I query find() with an array of IDs variable in mongoose?

I have an array p_id which holds ObjectId of a Schema named "Panel". Now I want to find candidates from "Candidate" schema which have parentPanel same as id's present in p_id array.
This is the candidateSchema:
var candidateSchema = new Schema ({
name: {
type: String,
required: true,
},
votedBy: [{
type: Schema.Types.ObjectId,
ref: 'User',
default: null,
}],
parentPanel: {
type: Schema.Types.ObjectId,
ref: 'Panel'
}
});
I tried something like this;
Candidate.find({parentPanel: {$in: [p_id]})
.then(candidates => {
res.send(candidates)
})
.catch(err=>console.log(err));
This is the error I'm getting:
message: 'Cast to ObjectId failed for value "[
5d8734d2bf53280d76a3915a, ' +
'5d8734d2bf53280d76a3915e ]" at path "parentPanel" for model ' +
'"Candidate"', name: 'CastError', stringValue: '"[ 5d8734d2bf53280d76a3915a, 5d8734d2bf53280d76a3915e ]"', kind:
'ObjectId', value: [ 5d8734d2bf53280d76a3915a,
5d8734d2bf53280d76a3915e ], path: 'parentPanel', reason:
undefined, model: Model { Candidate }

MongoDB/Mongoose update array within array with $addToSet

Good day all,
i'm trying to save image galleries where each image can have up to 5 tags associated with them. So in the Document the Gallery field is an array that has multiple values of which the Tag attribute which itself is an array of Tags.
I'm having issue saving an image where the user adds 2 or more tags for that picture. below this is what i have in my mongoose user schema
gallery : [{
origin : {type: String, trim: true, default: null},
uploadOn: {type: Date, Default: null},
title: { type: String, trim: true, default: null},
caption: { type: String, trim: true, default: null },
tag: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Imagetag', unique: true, sparse: true }],
imageLink: { type: String, trim: true }
}]
and this is my update script
var query = {username:'testUser'};
var options = { runValidators: true };
var toUpdate = {
$addToSet : {
gallery : {
origin : req.body.orgin,
uploadOn: new Date(),
title: req.body.title,
caption: req.body.caption,
tag: '59a5fea0382f1305841f0d86' // working
$addToSet: { tag: { $each: ['59a5fea0382f1305841f0d86', '59a5fea0382f1305841f0d88'] } } , // not working
$push: { tag: { $each: ['59a5fea0382f1305841f0d86', '59a5fea0382f1305841f0d88'] } } , // not working
imageLink: req.body.path
}
}
};
// proceed to update
var user = await User.findOneAndUpdate(query, toUpdate, options);
i have listed the different combination that i have tried without success. i do not want to have to make multiple calls to update the tags one by one for that same image.

Mongoose query in MEAN stack

I've installed the MEAN stack using the yeoman generator and I would like to implement a query that returns true if a document with a given value for a specific property exists.
It this is the model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var FirstSchema = new Schema({
field1: {
type: Number,
trim: true,
default: ''
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
});
var SecondSchema = new Schema({
field1: {
type: Number,
trim: true,
default: ''
},
field2: {
type: String,
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
});
mongoose.model('First', FirstSchema);
mongoose.model('Second', SecondSchema);
During the creation of Second objects, I assign the $scope.field2 = $stateParams.firstId;
The given query generated by yeoman in the client side is:
$scope.find = function() {
$scope.firsts = Firsts.query();
};
How query if First._id == Second.field2?

Is it possible to only populate certain fields MongoDB

I'm using the following model schema:
var AppointmentSchema = new Schema({
appointment_date: {type: Date},
created: {
type: Date,
default: Date.now
},
updated: {type: Date},
client: [{ type: Schema.Types.ObjectId, ref: 'User' }],
staff_id: [{ type: Schema.Types.ObjectId, ref: 'User' }],
cost:{
type: Number
},
jobDone:{
type: Boolean,
default: false
},
cancelled:{
type: Boolean,
default: false
}
});
Which clearly references the User model.
When I query I want to populate the client and staff data, but without some of the fields that they hold within that model.
So if the Users model is:
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
}
});
I would only want to populate with firstName and email (and omit the rest) is that possible?
To return a few specific fields returned for the populated documents, you need to pass the usual field name syntax as the second argument to the populate method:
Appointment
.findOne({ cancelled: true })
.populate('client', 'firstName displayName') // only return the User's firstName and displayName
.exec(function (err, appointment) {
if (err) return handleError(err);
console.log('The client name is %s', appointment.client.firstName);
// prints "The client name is Aaron"
console.log('The client display name is %s', appointment.client.displayName);
// prints "The client display name is aarontest'
})

Bad request in MEAN stack app trying to append to an array in a schema

I am trying to pass an array of interest rates to a mongoose schema consisting of accounts.
I want to store interest rates that change at certain dates.
However, when I trigger the create function my dev tools tell me I have done something bad:
**400 Bad Request**
I have been using this as a template.
The view: has been disconnected so that I only pass:
var interest = {
rate: 1,
date: Date.now()
};
The controller that does the updating:
// Create new Account
$scope.create = function() {
// Create new Account object
var account = new Accounts ({
name: this.name,
desc: this.desc,
interests: []
});
// PROBLEMATIC PART
// Store interest:
var interest = {
rate: 1,
date: Date.now()
};
account.interests.push(interest);
// PROBLEMATIC PART END
// Redirect after save
account.$save(function(response) {
$location.path('accounts/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
The mongoose schema:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
*
* Interest Rate Schema
*/
var InterestRate = new Schema({
rate:{
type: Number,
default: 0,
trim: true
},
date:{
type : Date,
default: '',
required: 'When is the interest to be updated',
trim: true
}
});
/**
* Account Schema
*/
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
[{ type : Schema.Types.ObjectId, ref: 'InterestRate' }],
amount:{
type: Number,
default:0,
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Account', AccountSchema);
you can try by leaving the interest rate as a frond end structure and not define it in the model, then in the account schema set interests as type of [] and just push the objects
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
type:[],
default:[]
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
just like this

Resources