Create case sensitive index with mongoDB? - mongodb

I'm trying to create case sensitive index with mongoDB version 3.4? I'm using the following query to create an index but still it allows me to insert data with different case?
db.Test.createIndex( { "type" : 1 },{ unique: true , collation: { locale: 'en' ,caseLevel:true ,strength: 3 } } )
in the above query i'm making Type as unique. First i inserted "apple" into the database and when i try to "apple" it throws duplicate error. but when i try to insert "Apple" it allows me to insert. for me while inserting "Apple" it should throws duplicate error.

Strength 2 will work
db.Test.createIndex({
type:1
},
{
collation:{
locale:"en",
strength:2
},
unique:true
}));

Related

Is there a way in mongoDB using db.runCommand, where i can insert multiple doc in collection only it's not present. if present, ignore that document

I am writing a migration script, which uses a db.runCommand to apply migration in mongoDb.
Something like this:
db.runCommand(
{
insert: "countries",
documents: [
{
"name": "Algeria"
},
{
"name": "Andorra"
},
{
"name" : "Angola"
}
]
}
)
let's say if Algeria is already present and Andorra along with Angola is not present in countries collection.
My requirement is we should be able to only insert only Andorra and Angola in countries collection as they are not present. Algeria should be ignored and no exception should be thrown.
How can we achieve this?
You have two options, I'll start with my preferred option:
I would start by creating a unique index on the name field.
Now when you try to insert a document that violates the uniqueness constraint it fails:
Inserting a duplicate value for any key that is part of a unique index, ... With ordered to false, the insert operation would continue with any remaining documents.
Let's understand how that affects the insert command via the ordered option:
Optional. If true, then when an insert of a document fails, return without inserting any remaining documents listed in the inserts array. If false, then when an insert of a document fails, continue to insert the remaining documents. Defaults to true.
This means that if you use the ordered: false option for the insert command, all inserts will "try" to execute even if one fails (in our case due to unique index violation).
To summarise what you have to do is 1. build a unique index on the name field, 2. add ordered: false option to the insert command like so:
db.runCommand(
{
insert: "countries",
documents: [
{
"name": "Algeria"
},
{
"name": "Andorra"
},
{
"name": "Angola"
}
],
ordered: false
}
)
The other option you have is to use an update command with the upsert option instead of the insert command, I would personally not choose this as it has more overhead:
db.runCommand(
{
update: "countries",
updates: [
{
q: {"name": "Algeria"},
u: {"name": "Algeria"},
upsert: true
},
{
q: {"name": "Andorra"},
u: {"name": "Andorra"},
upsert: true
},
{
q: {"name": "Angola"},
u: {"name": "Angola"},
upsert: true
},
]
}
)

Querying MongoDb's custom key & value with Index

I am trying to store key value data in MongoDb.
Key could be any string and I don't know about it anything more before storing, value could be any type (int, string, array). And I would like to have an index on such key & value.
I was looking on a (Multikey Index) over an array of my key-vals but looks like it can't cover queries over array fields.
Is it possible to have an index on a custom key & value in mongoDb and make queries with such operations as $exists and $eq and $gte, $lte, $and, $or, $in without COLLSCAN but through an IXSCAN stage?
Or maybe I need another Db for that?
I may have misunderstood your question but I think that this is precisely where MongoDB's strengths are - dealing with different shapes of documents and data types.
So let's say you have to following two documents:
db.test.insertMany([
{
key: "test",
value: [ "some array", 1 ]
},
{
key: 12.7,
values: "foo"
}
])
and you create a compound index like this:
db.test.createIndex({
"key": 1,
"value": 1
})
then the following query will use that index:
db.test.find({ "key": "test", "value": 1 })
and also more complicated queries will do the same:
db.test.find({ "key": { $exists: true }, "value": { gt: 0 } })
You can verify this by adding a .explain() to the end of the above queries.
UPDATE based on your comment:
You don't need the aggregation framework for that. You can simply do something like this:
db.test.distinct("user_id", { "key": { $exists: true } })
This query is going to use the above index. Moreover it can be made even faster by changing the index definition to include the "user_id" field like this:
db.test.createIndex({
"key" : 1.0,
"value" : 1.0,
"user_id" : 1
})
This, again, can be verified by running the following query:
db.test.explain().distinct("user_id", { "key": { $exists: true } })
If your key can be any arbitrary value, then this is impossible. Your best bet is to create an index on some other known field to limit the initial results so that the inevitable collection scan's impact is reduced to a minimum.

How to maintain the uniqueness based on a particular fieldin array Without using Unique index

I have the document like this.
[{
"_id" : ObjectId("aaa"),
"host": "host1",
"artData": [
{
"aid": "56004721",
"accessMin": NumberLong(1481862180
},
{
"aid": "56010082",
"accessMin": NumberLong(1481861880)
},
{
"aid": "55998802",
"accessMin": NumberLong(1481861880)
}
]
},
{
"_id" : ObjectId("bbb"),
"host": "host2",
"artData": [
{
"aid": "55922560",
"accessMin": NumberLong(1481862000)
},
{
"aid": "55922558",
"accessMin": NumberLong(1481861880)
},
{
"aid": "55940094",
"accessMin": NumberLong(1481861760)
}
]
}]
while updating any document, duplicate "aid" should not be added again in the array.
One option i got is using the unique index on artData.aid field. But building indexes is not preferred as i wont need it as per the requirement.
Is there any way to solve this?
Option 1: While designing Schema for that document use unique:true.
for example:
var newSchema = new Schema({
artData: [
{
aid: { type: String, unique: true },
accessMin: Number
}]
});
module.exports = mongoose.model('newSchema', newSchema );
Option 2: refer a link to avoid duplicate
As per this doc, you may use a multikey index as follows:
{ "artData.aid": 1 }
That being said, since you dont want to use a multikey index, another option for insertion is to
Query the document to find artData's that match the aid
Difference the result set with the set you are about to insert
remove the items that match your query
insert the remaining items from step 2
Ideally your query from step 1 wont return a set that is too large -- making this a surprisingly fast operation. That said, It's really based on the number of duplicates you assume you will be trying to insert. If the number is really high, the result of the query from step 1 could return a large set of items, in which case this solution may not be appropriate, but its all I've got for you =(.
My suggestion is to really re-evaluate the reason for not using multikey indexing

How can I specify uniqueness on multiple field in mongo, NOT combined?

I have the following JSON schema in MongoDB:
{"email": "example#gmail.com", "second_email": "example222#gmil.com"}
How can I enforce that both fields will be unique separately AND also be unique between them.
i.e the following document will not be valid:
{"email":"anotherone#gmail.com", "second_email":"example#gmail.com"}
Because example#gmail.com is already exists in another document in the other field.
Off the top of my head, no database can do this (use another column/field as source data for uniqueness constraint). You will need to do some reshaping of data to achieve this. The easiest way is a unique constraint on an array field.
> db.foo.createIndex({ emails: 1 }, { unique: true } )
> db.foo.insert({ emails: ['example#gmail.com', 'example222#gmail.com'] })
WriteResult({ "nInserted" : 1 })
> db.foo.insert({ emails: ['anotherone#gmail.com', 'example#gmail.com'] })
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.foo.$emails_1 dup key: { : \"example#gmail.com\" }"
}
})
Now, depending on your app logic, this emails array can even replace your original two fields. Or not. Up to you. If not, you'll need insert both the original fields and duplicate them in this array for the uniqueness check.
You need to create a a unique index on each field to enforce uniqueness for the fields.
db.collection.createIndex( { "email": 1 }, { "unique": true } )
db.collection.createIndex( { "second_email": 1 }, { "unique": true } )
That being said, MongoDB doesn't not provides a way to enforce uniqueness for two fields in the same documents. This is something you will need to do in your application using an if/else statement.
Another option as shown in this answer here is to use an indexed array field if you do not want to call the createIndex() method multiple times. But you still need to use logical condition processing if you don't want duplicate value in the array.
db.collection.createIndex( { "mails.email": 1, "mails.second_email": 1 }, { unique: true } )
db.collection.insert( { _id: 3, mails: [ { email: "example#gmail.com", second_email: "example222#gmil.com" } ] } )
now you created a "email - second email" pair combination for enforce uniqueness this two field.
Also, if you use bulk option you can set ordered as false to continue with remaining inserts when one fails.. insertMany({},{ordered: false})

How to ignore duplicate "_id" and insert unique "_id" in mongodb

I have a JSON structure at first insertion as
collection.insert(query.query, function(err, docs) {
callback(err,docs);
dbCon.close();
});
JSON Structure:
"employees":[
{"_id":1, "lastName":"Doe"},
{"_id":2, "lastName":"Smith"},
{"_id":3,"lastName":"Jones"}
]
When I first insert this JSON into mongodb, it gets inserted without any errors.
When I try insert again on the same database, with below JSON
"employees":[
{"_id":2, "lastName":"Smith"},
{"_id":5, "lastName":"Peter"},
{"_id":6,"``lastName":"James"}
]
Now the mondo db is throwing duplicate key error.
Is there any way where I can omit the "_id":2 and insert "_id":5 and "_id":6 into mongo?
Please help me..
You can perform an upsert in your case :
db.people.update(
{ name: "Andy" },
{
name: "Andy",
rating: 1,
score: 1
},
{ upsert: true }
)
If the first query gets a blank collection, that it will insert the data in this case if a Recrod with name Andy is not there, it will insert one.
In the first time, you insert a document
{"_id":2, "lastName":"Smith"}.
In the second time , you insert a document {"_id":2, "lastName":"Smith"}.
Their ids are the same ,not unique.
Suggest create id automatically by mongdb.
You can add the following code:
collection.findOne({"_id":2}.exec(function(err,result){
if(!result){
collection.insert(XXX);
}
}));