MongoDB duplicate index does not throw error - mongodb

I am new to MongoDB and trying to make MongoDB throw an error when I insert another document with the same index. According to this answer MongoDB should throw an error.
The steps I did are:
1.) Add an index to Name field. I verified that it is added:
> db.room.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.room"
},
{
"v" : 1,
"key" : {
"Name" : 1
},
"name" : "Name_1",
"ns" : "test.room"
}
]
2.) I tried to add document with the same name and was able to add it:
> db.room.find().pretty()
{
"_id" : 1,
"ModifiedDate" : ISODate("2017-02-12T10:59:35.394Z"),
"CreatedDate" : ISODate("2017-02-12T10:59:35.394Z"),
"Name" : "Sample"
}
{
"_id" : 2,
"ModifiedDate" : ISODate("2017-02-12T10:59:39.474Z"),
"CreatedDate" : ISODate("2017-02-12T10:59:39.474Z"),
"Name" : "Sample"
}
I am using C# MongoDB Driver 2.4.

You have to specify that the index you are creating is unique, otherwise MongoDB will not enforce it. You can do that with the C# driver using the CreateIndexOptions class.
roomCollection.Indexes
.CreateOne(
Builders<Room>.IndexKeys.Ascending(r => r.Name),
new CreateIndexOptions() { Unique = true });
Note that index creation will fail if there are currently duplicate names in the collection.

Related

how to list all the constraints for a mongodb collection?

I have a mongo db collection called students and when I tried to insert a record, I got an about duplicate studentNumber.
I want to run a command to show me all the constraints. I tried db.getCollectionInfos() and this is all it told me about the students collection
{
"name" : "students",
"type" : "collection",
"options" : {
},
"info" : {
"readOnly" : false,
"uuid" : UUID("70f19e72-bca2-4c86-aa2a-174cfa422d11")
},
"idIndex" : {
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_"
}
},
There's no mention that studentNumber is a unique field. Is there another command that I can run to list all the constraints on the students collection?

MongoDB PartialFilterExpression filter issue

I have a collection of items where a document looks something like this:
{
"source" : "rest",
"serviceCode" : "fluff",
"fluff" : "puff",
"systemEntryTime" : ISODate("2018-05-16T09:04:00.585Z")
}
I have an index with a TTL option for two weeks :
{
"v" : 1,
"key" : {
"systemEntryTime" : 1
},
"name" : "systemEntryTime_1",
"ns" : "storage.item",
"expireAfterSeconds" : NumberLong(1209600)
}
Now I want certain documents where source = "ftp" to have a different TTL. For this purpose I created the following index with a partialFilterExpression:
{
"v" : 1,
"key" : {
"systemEntryTime" : 1,
"source" : 1
},
"name" : "systemEntryTime_1_source_1",
"ns" : "storage.item",
"expireAfterSeconds" : NumberLong(1),
"partialFilterExpression" : {
"source" : {
"$eq" : "ftp"
}
}
}
Unfortunately this is not working, what am I doing wrong here? I have experimented with dropping the old index and using only this, but no documents a dropped according to the TTL (or any documents at all for that matter).

MongoDB Migrate all existing indexes to new database

I have a MongoDB development cluster where i create indexes over time as a part of development improvements. On Testing/Production MongoDB cluster also, i want to maintain the same indexes.
So how do i get all indexes of existing collections and create the same collection indexes on new database?
From mongo shell, switch to database from where you want to collect indexes
Step 1: Switch to existing DB and Run below script
> use my_existing_db
Below script loops through all the collections and constructs a run command for each collection.
var database = ‘my_new_db' // SHOULD ALWAYS MATCH DESTINATION DB NAME
db.getCollectionNames().forEach(function(collection){
var command = {}
var indexes = []
idxs = db.getCollection(collection).getIndexes()
if(idxs.length>1){
idxs.forEach(function(idoc){
if(idoc.name!='_id_'){
var ns = database+"."+idoc.ns.substr(idoc.ns.indexOf('.') + 1 )
idoc.ns = ns
indexes.push(idoc)
}
})
command['createIndexes'] = collection
command['indexes'] = indexes
print('db.runCommand(')
printjson(command)
print(')')
}
})
Script outputs runCommand's for each collection
Step 2: Switch to new db and execute runCommands. Done, Cheers!
> use my_new_db
runCommands will be something like this. You can run all the commands in one shot.
db.runCommand(
{
"createIndexes" : "foo",
"indexes" : [
{
"v" : 2,
"key" : {
"xy_point" : "2d"
},
"name" : "xy_point_2d",
"ns" : "my_new_db.foo",
"min" : -99999,
"max" : 99999
},
{
"v" : 2,
"key" : {
"last_seen" : 1
},
"name" : "last_seen_1",
"ns" : "my_new_db.foo",
"expireAfterSeconds" : 86400
},
{
"v" : 2,
"key" : {
"point" : "2dsphere"
},
"name" : "point_2dsphere",
"ns" : "my_new_db.foo",
"background" : false,
"2dsphereIndexVersion" : 3
}
]
}
)
db.runCommand(
{
"createIndexes" : "bar",
"indexes" : [
{
"v" : 2,
"unique" : true,
"key" : {
"date" : 1,
"name" : 1,
"age" : 1,
"gender" : 1
},
"name" : "date_1_name_1_age_1_gender_1",
"ns" : "my_new_db.bar"
}
]
}
)

MongoDB - How to remove duplicates

I have a collection which have many duplicates due to the routines that populated it in the first place. How to dedupe these?
e.g.
{ "_id" : ObjectId("531a5fe448757e00244096fa"), "code" : "ap", "name" : "[Almost Perfect]", "value" : "[u'*']" }
{ "_id" : ObjectId("531a731148757e17587a6e04"), "code" : "ap", "name" : "[Almost Perfect]", "value" : "[u'*']" }
{ "_id" : ObjectId("531a7bb848757e1f7c0ca702"), "code" : "ap", "name" : "[Almost Perfect]", "value" : "[u'*']" }
I want it to be just one (don't care which objectID gets picked)
{ "_id" : ObjectId("531a5fe448757e00244096fa"), "code" : "ap", "name" : "[Almost Perfect]", "value" : "[u'*']" }
You should use an Index over you code field:
db.<collection>.ensureIndex({'code' : 1}, {unique : true, dropDups : true})
unique will ensure you will not have duplicates anymore.
dropDups will delete all your duplicate documents when the ensureIndex operation is run

can't shard a collection on mongodb

I have a db ("mydb") on mongo that contains 2 collections (c1 and c2). c1 is already hash sharded. I want to shard a second collection the same way. I get the following error :
use mydb
sh.shardCollection("mydb.c2", {"LOG_DATE": "hashed"})
{
"proposedKey" : {
"LOG_DATE" : "hashed"
},
"curIndexes" : [
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mydb.c1",
"name" : "_id_"
}
],
"ok" : 0,
"errmsg" : "please create an index that starts with the shard key before sharding."
So I did
db.c2.ensureIndex({LOG_DATE: 1})
sh.shardCollection("mydb.c2", {"LOG_DATE": "hashed"})
Same error but it shows the new index.
"proposedKey" : {
"LOG_DATE" : "hashed"
},
"curIndexes" : [
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mydb.c2",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"LOG_DATE" : 1
},
"ns" : "mydb.c2",
"name" : "LOG_DATE_1"
}
],
"ok" : 0,
"errmsg" : "please create an index that starts with the shard key before sharding."
Just to be sure, I run :
db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "mydb.c1", "name" : "_id_" }
{ "v" : 1, "key" : { "timestamp" : "hashed" }, "ns" : "mydb.c1", "name" : "timestamp_hashed" }
{ "v" : 1, "key" : { "_id" : 1 }, "ns": "mydb.c2", "name" : "_id_" }
{ "v" : 1, "key" : { "LOG_DATE" : 1 }, "ns" : "mydb.c2", "name" : "LOG_DATE_1" }
I try again the same commands on admin and it fails with the same error.
Then I tried on admin without "hashed" and it worked.
db.runCommand({shardCollection: "mydb.c2", key: {"LOG_DATE": 1}})
Problem : now my collection is sharded on something that is not hashed and I can't change it (error : "already sharded")
What was wrong with what I did ?
How can I fix this ?
Thanks in advance
Thomas
The problem initially was that you did not have a hashed index what you proposed to use for sharding this is the error message is about. After the first error message, when you created an index which is
{
"v" : 1,
"key" : {
"LOG_DATE" : 1
},
"ns" : "mydb.c2",
"name" : "LOG_DATE_1"
}
You still just have an ordinary index which is not a hashed one. If you would do this :
db.c2.ensureIndex({LOG_DATE: "hashed"})
Instead of this :
db.c2.ensureIndex({LOG_DATE: 1})
Than would be a hashed index. As you can see in the output of the db.system.indexes.find() on the other collection you have a hashed index for the timestamp i assume this is the shard key for that collection.
So if you have no data in the c2 collection:
db.c2.drop()
db.createCollection('c2')
db.c2.ensureIndex({LOG_DATE: "hashed"})
sh.shardCollection("mydb.c2", {"LOG_DATE": "hashed"})
This will work properly.