mongoose compound index for fixed value field - mongodb

Is it possible to make a compound index, where one of the fields have a fixed value?
Let's say I want to avoid users using the same e-mail for different accounts, but just for regular user accounts, and I want to allow admins to use the mail in as many places as they want, and even have a regular user account and an administrative account using the same e-mail
User.index({ username: 1, email: 1 }, { unique: true })
Is not useful, since it will not allow admins to reuse the email. Is it possible to do something like?
User.index({ role: "regular_user", username 1, email: 1}, { unique: true });

Luis,
In regards to the example that you gave. If you create a unique compound index, individual keys can have the same values, but the combination of values across the keys that exist in the index entry can only appear once. So if we had a unique index on {"username" : 1, "role" : 1}. The following inserts would be legal:
> db.users.insert({"username" : "Luis Sieira"})
> db.users.insert({"username" : "Luis Sieira", "role" : "regular"})
> db.users.insert({"username" : "Luis Sieira", "role" : "admin"})
If you tried to insert a second copy of any of the above documents, you would cause a duplicate key exception.
Your Scenarios
I think that if you added an allowance field to your schema. When you do inserts for admins for new accounts. You can add a different value for their admin allowance. If you added unique index for {"username":1,"email":1, "allowance" : 1}
You could make the following inserts, legally:
>db.users.insert({"username" : "inspired","email": "i#so.com", "allowance": 0})
>db.users.insert({"username" : "inspired","email": "i#so.com", "allowance": 1})
>db.users.insert({"username" : "inspired","email": "i#so.com", "allowance": 2})
>db.users.insert({"username" : "inspired","email": "i#so.com", "allowance": 3})
Of course, you'll have to handle certain logic from the client, but this will allow you to use an allowance code of 0 for regular accounts and then allow you to save a higher allowance code (incrementing it or adding custom value for it) each time an admin creates another account.
I hope this offers some direction with using unique compound indexes.

You are on the right track. First things first, if you define an index with the role like this
User.index({role: 1, username: 1, email: 1}, { unique: true });
Mongo will use null for documents that do not specify the role field. If you insert an user without specifying the role and try to add it again, you will get an error because the three fields already exist in the database. So you can use this to your advantage by not including a role (or you can use a predefined value for better reading, like you proposed as regular_user).
Now, the tricky part is forcing the index to permit admins to bypass the uniqueness constraint. The best solution would be to generate a some hash and add it to the role. So, if you just add admins with roles like admin_user, you won't bypass the constraint. Meanwhile, using a role like admin_user_635646 (always with varying suffix) will allow you to insert the same admin multiple times.

Related

How do I remove the duplicate Key check before insert in mongoDB?

I use mongoDB to manage my DB for a yearly contest. Every year many users just renew their registration. MongoDB rejects duplicate emails, therefore they cannot register if they participated any of the edition of early years.
My question, is there any way to remove that limitation? Or maybe change the dup-key-check to be i.e. the "_id" (or whatever) instead of the "email"?
Apart from the mandatory _id field, MongoDB will only enforce uniqueness based on additional unique indexes that have been created. In your situation it sounds like there may be a unique index defined on { email: 1 }.
If that is not the logic that you wish to enforce, then you should drop that index and replace it with a different one. How exactly you define that really depends on your desired application logic. If you had a registrationYear field, for example, perhaps a compound unique index on both of those fields ({ email: 1, registrationYear: 1 }) would be appropriate.
But this probably isn't the only way to solve the problem. An alternative approach may be to combine a unique index with a partial index. With this approach, you could define as index as follows assuming that there is some active field in the document that becomes false after the specified amount of time:
db.foo.createIndex({ email: 1}, { unique: true, partialFilterExpression: { active: true } })
Such an index would only include documents that were currently considered active therefore only enforcing uniqueness on them. Once it was time to renew and an old document was no longer active the database would accept a new one.
Another alternative approach would be to just update the existing documents rather than creating new ones. Again this depends on what exactly you are trying to achieve, but you could use a similar approach of marking a document as no longer active and having the registration process perform an upsert (either an insert or an update).
Finally, if you don't need historical information at all then you could additionally do some sort of archival or deletion (perhaps via a TTL index) to expire the old documents.

Using unique identifier in MongoDB with different name

I'm going to set up my first Mongo DB collection which will use its own identifier for the customers (the tax id). I understand I can provide myself unique indexes to my Collections, however is it possible to name it differently (instead of "_id" ) ? If so, will I get automatic index creation, or should I create them explicitly ?
Thanks!
Please see here.
You can run something like db.accounts.ensureIndex( { "tax-id": 1 }, { unique: true } ).

In NoSql how to ensure uniqueness of two columns, for example Username and Email should be unique

Say I want to implement a simple NoSql database containing a list of users. I want both the username and the email of the user to be unique. Which NoSql database can achieve this.
This solution is valid in MongoDB.
You need to put a unique index on these fields:
db.collection.ensureIndex({
username: 1,
email : 1
}, {
unique: true
})
Whenever you try to add a document with a username and email combination that already exists, an exception will be raised. You just need to catch the exception and tell this to customer.
P.S. if you want these fields to be individually unique, you can instead ensure two indexes:
db.collection.ensureIndex({ username: 1 }, { unique: true });
db.collection.ensureIndex({ email : 1 }, { unique: true });
In Dynamo you can't, at least in a direct way. That's up to your model. For example, if your key is the username, and the range key is the email, you will be able to do it. However, if one of these fields are in the value, you won't be able to achieve uniqueness
you can user the incr command on a key in redis .
you will have something like thing like this
127.0.0.1:6379> INCR key
(integer) 1
127.0.0.1:6379> INCR key
(integer) 2
127.0.0.1:6379> INCR key
(integer) 3
127.0.0.1:6379> INCR key
(integer) 4
redis is very interressing database who can manage cache (like memcache but with persistence with a lot of keys types) and pub/sub.Can be very light and very effective.
I use it on a lot of case (Session, InterProcessCommunication, persistance, realtime messaging, light data storing, geopos calculation in lua,...) i love it.
more infomation

MongoDB : How do the stored objects are affected by model changes?

I am considering to move to mongoDB but I lack some certain basic understanding of the thing. My main question is "How do the stored objects are affected by model changes?". Here is a scenario to better understand what I want to know :
I create a "User" model with first_name, last_name, email attributes.
I create 25 users in my application that are stored in mongo (so they get stored as {first_name: "xxx", last_name: "yyy", email: "zzz"})
I add an attribute to my "User" model : username
I create 25 new users in my application (so they get stored as {first_name: "xxx", last_name: "yyy", email: "zzz", username: "xyz"})
I remove the "first_name" and "last_name" attributes from the "User" model.
I update the email address of 5 of the first 25 users.
So here are my questions :
After adding the "username" attribute to "User" model, what happens to the first 25 objects? Do they receive the "username" attribute in their BSON definition with an empty value? My understanding is they are simply left unnafected.
When I remove the "first_name" and "last_name" attributes from the "User" model, what happens to the existing 50 users? I guess the same answers as #1 applies.
After I updated the email addresses of the 10 records, what happens to the 5 firsts? Do they get the "username" added, "first_name" and "last_name" removed and their email addresses updated? Or simply their email addresses updated?
Your intuition is correct. MongoDB requires you to create and enforce the data model in your application (i.e., outside the database).. I think this is one of the biggest mental hurdles to get over when making the switch from SQL databases.
So to answer your questions
The original 25 User objects will not automatically receive a "username" attribute. You will either need to manually update the existing users to add a username or update the model to handle the case where no username exists.
Same as above. You will either need to manually update the existing records to remove the first_name and last_name attributes or wait until the object is updated to a future version that doesn't include them.
It depends on how you do the update. You can either update by replacing the entire record or by using modifiers to change individual fields. If you replace the entire record, then the current version of the model will be saved. If you modify the "email" attribute directly, then the other fields will not be changed.

MongoDB: Unique Key in Embedded Document

Is it possible to set a unique key for a key in an embedded document?
I have a Users collection with the following sample documents:
{
Name: "Bob",
Items: [
{
Name: "Milk"
},
{
Name: "Bread"
}
]
},
{
Name: "Jim"
},
Is there a way to create an index on the property Items.Name?
I got the following error when I tried to create an index:
> db.Users.ensureIndex({"Items.Name": 1}, {unique:true});
E11000 duplicate key error index: GroceryGuruApp.Users.$Items.Name_1 dup key: {
: null }
Any suggestions? Thank you!
Unique indexes exist only across collection. To enforce uniqueness and other constraints across document you must do it in client code. (Probably virtual collections would allow that, you could vote for it.)
What are you trying to do in your case is to create index on key Items.Name which doesn't exist in any of the documents (it doesn't refer to embedded documents inside array Items), thus it's null and violates unique constraint across collection.
You can create a unique compound sparse index to accomplish something like what you are hoping for. It may not be the best option (client side still might be better), but it can do what you're asking depending on specific requirements.
To do it, you'll need to create another field on the same level as Name: Bob that is unique to each top-level record (could do FirstName + LastName + Address, we'll call this key Identifier).
Then create an index like this:
ensureIndex({'Identifier':1, 'Items.name':1},{'unique':1, 'sparse':1})
A sparse index will ignore items that don't have the field, so that should get around your NULL key issue. Combining your unique Identifier and Items.name as a compound unique index should ensure that you can't have the same item name twice per person.
Although I should add that I've only been working with Mongo for a couple of months and my science could be off. This is not based on empirical evidence but rather observed behavior.
More on MongoDB Indexes
Compound Keys Indexes
Sparse Indexes
An alternative would be to model the items as a hash with the item name as the key.
Items: { "Milk": 1, "Bread": 1 }
I'm not sure about whether you're trying to use the index for performance or purely for the constraint. The right way to approach depends on your use cases, and determining whether the atomic operations are enough to keep your data consistent.
The index will be across all Users and since you asked it for 'unique', no user will be able to have two of the same named item AND no two users will be able to have the same named Item.
Is that what you want?
Furthermore, it appears that it's objecting to two Users having a 'null' value for Items.Name, clearly Jim does, is there another record like that?
It would be unusual to require uniqueness on an indexed collection like this.
MongoDB does allow unique indexes where it indexes only the first of each value, see
http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues, but I suspect the real solution is to not require uniqueness in this case.
If you want to ensure uniqueness only within the Items for a single user you might want to try the $addToSet option. See http://www.mongodb.org/display/DOCS/Updating#Updating-%24addToSet
You can use use findAndModify to create a sequence/counter function.
function getNextSequence(name) {
var ret = db.counters.findAndModify({
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true,
upsert: true
});
return ret.seq;
}
Then use it whenever a new id is needed...
db.users.insert({
_id: getNextSequence("userid"),
name: "Sarah C."
})
This is from http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/. Check it out.