compound index not working? - javascript

I am trying to create a compound index using mongoose:
var ProjectSchema = new mongoose.Schema({
name: {type: String, required: true},
user: {type: mongoose.Schema.ObjectId, ref: 'User', required: true}
});
ProjectSchema.index({user: 1, name: 1}, {unique: true});
after that I dropped the old database in mongo
db.dropDatabase()
but I still can insert multiple documents with the same name and user id. why?
the index that it created shows in mongo as
> db.projects.getIndexes();
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mydatabase.projects",
"name" : "_id_"
}
]

This is the pure mongo console function and it works,
Click Here for more detail. This is not descibe in mongoose's API.
I think it might be work.
db.collection.ensureIndex( { a: 1 }, { unique: true, dropDups: true } )

Actually your index does not appear to have been created. You are showing just the default primary key. Your output from .getIndexes() should be more like:
> db.projects.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "project.projects",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"user" : 1,
"name" : 1
},
"unique" : true,
"ns" : "project.projects",
"name" : "user_1_name_1",
"background" : true,
"safe" : null
}
]
There might be something up in your code, but this works for me:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/project');
var db = mongoose.connection;
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: { type: String, required: true },
info: String
});
var ProjectSchema = new Schema({
name: { type: String, required: true},
user: { type: Schema.ObjectId, ref: 'User', required: 'true'}
});
ProjectSchema.index({ user: 1, name: 1}, { unique: true });
var User = mongoose.model( "User", UserSchema );
var Project = mongoose.model( "Project", ProjectSchema );
var user = new User({ name: "me" });
user.save(function(){
var project = new Project({ name: "Project1", user: user._id });
project.save(function(err, project, numAffected){
if (err) { // Should be fine
console.log(err);
}
console.log("First project created");
User.findOne({}).exec(function(err, user) {
console.log(user._id);
var project = new Project({ name: "Project1", user: user._id });
project.save(function(err, project, numAffected){
if (err) {
console.log(err); // Expect a problem here
}
console.log({ project: project, num: numAffected });
});
});
});
});

I had the exact same problem and this Github issue explained what was happening.
Firstly, compound indexes are only created after ensureIndex() is called. The problem for me is that I was using an import script that would drop my database and re-create it. ensureIndex() is not called until the server is restarted, so the compound index was not re-created after this.
The solution for me was to not drop my database in my import script, but instead iterate through my models and remove all the documents. That way the data was destroyed, but the indexes remained and hence the compound index would work.

I just had this problem, the compound index was not created at startup and I was checking the mongo logs, I could see that it was starting the build of the index but nothing was created, no errors etc...
Then I tried to manually create the index - in mongo console - and here I got an error (duplicate error in my case), so I removed the duplicates and I was able to create the index. I don't know why this was not popping up on my mongo logs.
Mongo v4

Related

MongoError: E11000 duplicate key error collection: workflow.compnies index: username_1 dup key: { username: null }

This type of question has asked many times .I have tried with every answer. In most of the case answer was like delete user index that is created by mongo automatically. I did it too many times. But everytime when I made request on server its created again(index).
when I write db.compnies.getIndexes().I get
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_"
},
{
"v" : 2,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"background" : true
}
]
After deletion by db.compnies.dropIndexes({"username":1}).I get
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ] as a db.compnies.getIndexes().
after every new request above process is repeated.I am facing this error since last two days.I am not able to submit my data.
please help me.
Thank you.
here is my user model:
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
// const findOrCreate = require('mongoose-findorcreate');
const logoSchema=new mongoose.Schema({
url:String,
filename:String
});
const UserSchema = new mongoose.Schema({
email: {
type: String,
},
username:{
type:String,
unique:false
},
// password:{
// type:String,
// },
googleId : {
type : String,
} ,
name : {
type : String,
} ,
firstName : {
type : String,
} ,
lastName : {
type : String,
},
age:{
type:String
},
compny:{
type:String
},
// logo :[logoSchema],
logo: {
type: String,
required: [true, "Uploaded file must have a name"],
},
createdAt:{
type: Date,
default : Date.now
}
});
UserSchema.plugin(passportLocalMongoose);
// UserSchema.plugin(findOrCreate);
const User = mongoose.model('User', UserSchema);
module.exports = User;
Here is my company model:
const mongoose=require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
// const ImageSchema = new mongoose.Schema({
// url: String,
// filename: String
// });
const compnySchema= new mongoose.Schema({
name:{
type:String,
// required:true
},
location:{
type:String,
// required:true
},
category:{
type:String,
// required:true
},
about:{
type:String
},
logo: {
type: String,
required: [true, "Uploaded file must have a name"],
},
count:{
type:Number
}
});
compnySchema.plugin(passportLocalMongoose);
const Compny= mongoose.model("Compny", compnySchema);
module.exports=Compny;
I was able to reproduce your condition. I recreated a node program...
// npm install mongoose
// npm install passport-local-mongoose
var mongoose = require('mongoose');
const passportLocalMongoose = require("passport-local-mongoose");
mongoose.connect("mongodb://localhost:27017/nodetest", {useNewUrlParser: true, useUnifiedTopology: true});
var db = mongoose.connection;
//Bind connection to error event (to get notification of connection errors)
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
const compnySchema= new mongoose.Schema({
name:{
type:String,
// required:true
},
location:{
type:String,
// required:true
},
category:{
type:String,
// required:true
},
about:{
type:String
},
logo: {
type: String,
required: [true, "Uploaded file must have a name"],
},
count:{
type:Number
}
});
compnySchema.plugin(passportLocalMongoose);
const Compny= mongoose.model("Compny", compnySchema);
module.exports=Compny;
let compny = new Compny;
compny.name = "some company";
compny.logo = "some logo";
compny.save(function(err) {
console.log(err);
});
If I run this program twice I get a duplicate key exception. This is because of passport. The program passport is enforcing a unique index on field username. But you don't have a field called username. This means the first record will get added with a null value (missing) for field username in the document. The second document inserted also has a null (missing) value for the field username and thus violates the uniqueness constraint.
If the field username does not exist in the schema passport will automatically add a unique index. But if the field does exist in the schema it will not add an index for the field - unique or not unique. I suppose it is expecting the full definition of indexes including the unique attribute to be applied to the schema definition if the field username exists.
Advice:
Do not apply passport to the companies collection
Do use passport on the users collection.

MongoError: E11000 duplicate key error collection with passport

I have the following userSchema
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var userSchema = new mongoose.Schema({
email: String,
password: String,
userName: String,
fname: String,
lname: String,
userType: Number,
subscribedThreads: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Threads"
}
]
});
// add passport methods
userSchema.plugin(passportLocalMongoose);
// export modules to be used by the file requiring it
module.exports = mongoose.model("Users",userSchema);
The first entry into the collection occurs as it should but the next ones give
{ [MongoError: E11000 duplicate key error collection: KManV3.users
index: username_1 dup key: { : null }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
driver: true,
code: 11000,
index: 0,
errmsg: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
getOperation: [Function],
toJSON: [Function],
toString: [Function]
}
Also, dbname.users.getIndexes() gives:
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "KManV3.users"
},
{
"v" : 1,
"key" : {
"password" : 1
},
"name" : "password_1",
"ns" : "KManV3.users",
"background" : true
},
{
"v" : 1,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "KManV3.users",
"background" : true
}
]
Apparently every property of schema has been set as unique and I can't add data into collections even if the data is totally different. I'm not sure if it's due to integration of passport.
Looking at the options for passport-local-mongoose:
usernameField: specifies the field name that holds the username. Defaults to 'username'.
usernameUnique : specifies if the username field should be enforced to be unique by a mongodb index or not. Defaults to true.
Which explains why your collection has a unique index on the (non-existent-in-your-schema) username field.
If you don't actually set this field in documents that you add to the database, MongoDB will use null, and once the first document has been inserted, a subsequent document (also with the field value null for username) will throw an E11000 error.
So first, remove the index on username (and also password, I assume you once marked that field as unique in your schema), and set the proper field name for passport-local-mongoose to use:
userSchema.plugin(passportLocalMongoose, { usernameField : 'userName' });
(or email, if you want that field to be used as unique user identifier)
Error reason - The index is not present in your collection, in which you are trying to insert.
Solution - drop that collection and run your program again.

MongoDB index search works in console, but not from browser

All of this was working yesterday so I'm really not sure whats wrong. I'v searched on SO and been through the docs and steps a number of times but I havnt got it to work. Any help much appreciated as always!
If I type db.movies.find({ '$text': { '$search': 'elephant' } }) into the shell, it returns a list of titles with 'elephant' in the title. But if I run the same search from my browser it crashes the node server and I get MongoError: text index required for $text query.
The error comes from the error response from the find():
Movie.find(
{ '$text': { '$search': 'elephants' } },
(err, movies) => {
if (err) throw err; // MongoError: text index required for $text query
if (!movies) {
res.json({
data: null,
success: false,
message: 'No movies data'
});
} else {
res.json({
success: true,
data: movies
});
}
})
The index on my DB looks like this:
{
"v" : 2,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"name" : "title_text",
"ns" : "db.movies",
"weights" : {
"title" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 3
}
I also have mongoose schemas defined and I'm using an auto increment plugin to increment a custom id field on each movie save. (Saving movies works, so I am connecting to the DB ok)
mongoose.model('Job', new Schema({
id: Number,
title: String,
desc: String,
genre: String
})
.index({ title: 'text' })
.plugin(autoIncrement.mongoosePlugin));
As pointed out in the comments by #Chris Satchell
Adding the index to the mongoose schema solves this.
instead of:
mongoose.model('Job', new Schema({
id: Number,
title: String,
desc: String,
genre: String
})
do this:
mongoose.model('Job', new Schema({
id: Number,
title: { type: String, text: true },
desc: String,
genre: String
})
even though I still had .index({ title: 'text' }) on the Schema, you still need to define the { type: String, text: true } on the property.

Create mongoose schema and insert document

I'm new to mongo and mongoose. I need to create schema from this object
trailers: [
{
id: 310131,
results: [
{
id: "564b9086c3a3686026004542",
iso_639_1: "en",
key: "gy_-pupKvxg",
name: "The Witch Official Trailer 1 2016 HD",
site: "YouTube",
size: 1080,
type: "Trailer"
},
{
id: "56aab2b19251417e110008b2",
iso_639_1: "en",
key: "feRupW34rUU",
name: "Trailer 2",
site: "YouTube",
size: 1080,
type: "Trailer"
}
]
}
],
Here is how I am doing it at the moment
// My Schema
var movieSchema = new mongoose.Schema({
....
...
..
.,
trailers : [
{
id: Number,
results : [
{
id: String,
iso_639_1: String,
key: String,
name: String,
site: String,
size: Number,
type: String,
}
],
_id : false
}
],
....
..
.
});
var Movie = mongoose.model('Movies', movieSchema);
// Insert movie into schema and save to database
movies.forEach(function(m) {
var movie = new Movie({
....
...
..
.,
trailers : m.trailers ? m.trailers : "",
....
...
..
.
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
}, this);
But I am doing it wrong can anyone spot or tell me how to insert each movie into schema object. Thanks in advance.
Per mongoose subdoc, please try to use .push to push trailers to movies. Here are the sample codes.
movies.forEach(function(m) {
var movie = new Movie({
....
//trailers : m.trailers ? m.trailers : "",
....
});
m.trailers.forEach(function(t){
movie.trailers.push(t);
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
});
According to me this should be your schema :
var movieSchema = new mongoose.Schema({
trailers: [
....
........
....
_id: Number,
results: [{
iso_639_1: String,
key: String,
name: String,
site: String,
size: String,
type: String
}]
........
....
]
});
Looking at your object, what I suggest is :
You should assign the _id field of the trailers array the Number that you currently assign to id field. And remove the id field from the schema.
_id field uniquely identifies a document inside a collection. So you should use it instead of id field that you created.
Secondly, you should let MongoDB create an _id field for your results array objects. That's why I haven't included an _id field in the results array object.
Next, to create new documents and save them in your collection, use your logic :
var Movie = mongoose.model('Movies', movieSchema);
// Insert movie into schema and save to database
movies.forEach(function(m) {
var movie = new Movie({
....
...
..
.,
(m.trailers) ? trailers = m.trailers : trailers = null,
....
...
..
.
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
}, this);
What's wrong with your logic is that you're trying to use ternary operator to check if m.trailers exist and if it does, you want to assign it to trailers array, and null otherwise. What you are using is :
trailers : m.trailers ? m.trailers : "",
What you should be using instead is :
(m.trailers) ? trailers = m.trailers : trailers = null,
Please do check it and let me know if it works.

Mongodb: Can't append to array using string field name

i am trying to push inside a subarray using $push but got a Mongo error, and not able to get through this after considerable search on google, and findOneAndUpdate didn't worked out so i used find and update separately
{ [MongoError: can't append to array using string field name: to]
name: 'MongoError',
err: 'can\'t append to array using string field name: to',
code: 13048,
n: 0,
lastOp: { _bsontype: 'Timestamp', low_: 2, high_: 1418993115 },
Schema:
var NetworkSchema = new Schema({
UserID: {
type: Schema.Types.ObjectId,
ref: 'User'
},
NetworkList: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
NetworkRequest: [{
from: [{
type:Schema.Types.ObjectId,
ref: 'User'
}],
to: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}]
});
Document:
{
"UserID" : ObjectId("549416c9cbe0e42c1adb42b5"),
"_id" : ObjectId("549416c9cbe0e42c1adb42b6"),
"NetworkRequest" : [
{
"from" : [],
"to" : []
}
],
"NetworkList" : [],
"__v" : 0
}
Controller:
exports.update = function(req,res) {
var network = req.network;
var query={'UserID':req.body.UserID};
var update = {$push:{'NetworkRequest.to': req.body.FriendID}};
Network.find(query,function(err){
if (err) {
console.log(err);
return err;
} else {
}
});
Network.update(query,update,{upsert:true},function(err,user){
console.log(user);
if (err) {
console.log(err);
return err;
} else {
console.log('User'+user);
}
});
};
Everything #cbass said in his answer is correct, but since you don't have a unique identifier in your NetworkRequest element to target, you need to do it by position:
var query = {'UserID': req.body.UserID};
var update = {$push:{'NetworkRequest.0.to': req.body.FriendID}};
Test.update(query, update, {upsert: true}, function(err, result) { ... });
'NetworkRequest.0.to' identifies the to field of the first element of the NetworkRequest array.
Your query var query={'UserID':req.body.UserID}; identifies the document you want to edit. Then you need another query to identify which object in the NetworkRequest array that the UserID should be pushed into. Something like below:
var query = {
'UserID':req.body.UserID,
'NetworkRequest._id': ObjectId(someNetworkRequestId)
};
Then use this update query containing $ which is the index of the object in the nested array(NetworkRequest)
var update = {
$push:{
'NetworkRequest.$.to': req.body.FriendID
}
};

Categories

Resources