diff options
author | Aaron <aaron@10gen.com> | 2009-04-20 13:51:54 -0400 |
---|---|---|
committer | Aaron <aaron@10gen.com> | 2009-04-20 13:51:54 -0400 |
commit | 80847b561c5851fa763866af06bb021af893f31a (patch) | |
tree | 4b6c080eae2f6ab024ab1d4cbe61d19245746f57 | |
parent | c34ef0f68d7f0dd493bdd2e50798f2c0211a71a7 (diff) | |
download | mongo-80847b561c5851fa763866af06bb021af893f31a.tar.gz |
add unique option when creating index in c++, js drivers; basic unique key unit tests
-rw-r--r-- | client/dbclient.cpp | 5 | ||||
-rw-r--r-- | client/dbclient.h | 6 | ||||
-rw-r--r-- | dbtests/perf/perftest.cpp | 8 | ||||
-rw-r--r-- | dbtests/queryoptimizertests.cpp | 2 | ||||
-rw-r--r-- | dbtests/querytests.cpp | 35 | ||||
-rw-r--r-- | jstests/index8.js | 30 | ||||
-rw-r--r-- | mongo.xcodeproj/project.pbxproj | 2 | ||||
-rw-r--r-- | shell/collection.js | 41 |
8 files changed, 111 insertions, 18 deletions
diff --git a/client/dbclient.cpp b/client/dbclient.cpp index 43102f64e93..292ced6ca29 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -518,7 +518,7 @@ namespace mongo { say( toSend ); } - bool DBClientBase::ensureIndex( const string &ns , BSONObj keys , const string & name ) { + bool DBClientBase::ensureIndex( const string &ns , BSONObj keys , bool unique, const string & name ) { BSONObjBuilder toSave; toSave.append( "ns" , ns ); toSave.append( "key" , keys ); @@ -556,6 +556,9 @@ namespace mongo { toSave.append( "name" , ss.str() ); cacheKey += ss.str(); } + + if ( unique ) + toSave.appendBool( "unique", unique ); if ( _seenIndexes.count( cacheKey ) ) return 0; diff --git a/client/dbclient.h b/client/dbclient.h index cb6825a9f9a..21d1485b011 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -542,12 +542,14 @@ namespace mongo { /** Create an index if it does not already exist. ensureIndex calls are remembered so it is safe/fast to call this function many times in your code. - @param name if not isn't specified, it will be created from the keys (recommended) + @param ns collection to be indexed @param keys the "key pattern" for the index. e.g., { name : 1 } + @param unique if true, indicates that key uniqueness should be enforced for this index + @param name if not isn't specified, it will be created from the keys (recommended) @return whether or not sent message to db. should be true on first call, false on subsequent unless resetIndexCache was called */ - virtual bool ensureIndex( const string &ns , BSONObj keys , const string &name = "" ); + virtual bool ensureIndex( const string &ns , BSONObj keys , bool unique = false, const string &name = "" ); /** clears the index cache, so the subsequent call to ensureIndex for any index will go to the server diff --git a/dbtests/perf/perftest.cpp b/dbtests/perf/perftest.cpp index e995a9347e8..3d383796277 100644 --- a/dbtests/perf/perftest.cpp +++ b/dbtests/perf/perftest.cpp @@ -111,7 +111,7 @@ namespace Insert { const char *names = "aaaaaaaaaa"; for( int i = 0; i < 10; ++i ) { client_->resetIndexCache(); - client_->ensureIndex( ns_.c_str(), BSON( "_id" << 1 ), names + i ); + client_->ensureIndex( ns_.c_str(), BSON( "_id" << 1 ), false, names + i ); } } void run() { @@ -612,7 +612,7 @@ namespace Plan { const char *names = "aaaaaaaaaa"; for( int i = 0; i < 10; ++i ) { client_->resetIndexCache(); - client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), names + i ); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); } lk_.reset( new dblock ); setClient( ns_.c_str() ); @@ -635,7 +635,7 @@ namespace Plan { const char *names = "aaaaaaaaaa"; for( int i = 0; i < 10; ++i ) { client_->resetIndexCache(); - client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), names + i ); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); } lk_.reset( new dblock ); setClient( ns_.c_str() ); @@ -654,7 +654,7 @@ namespace Plan { const char *names = "aaaaaaaaaa"; for( int i = 0; i < 10; ++i ) { client_->resetIndexCache(); - client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), names + i ); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); } lk_.reset( new dblock ); setClient( ns_.c_str() ); diff --git a/dbtests/queryoptimizertests.cpp b/dbtests/queryoptimizertests.cpp index 52569045048..85570e7eb48 100644 --- a/dbtests/queryoptimizertests.cpp +++ b/dbtests/queryoptimizertests.cpp @@ -263,7 +263,7 @@ namespace QueryOptimizerTests { ss << indexNum_++; string name = ss.str(); client_.resetIndexCache(); - client_.ensureIndex( ns(), key, name.c_str() ); + client_.ensureIndex( ns(), key, false, name.c_str() ); NamespaceDetails *d = nsd(); for( int i = 0; i < d->nIndexes; ++i ) { if ( d->indexes[ i ].indexName() == name ) diff --git a/dbtests/querytests.cpp b/dbtests/querytests.cpp index a6046e2ab89..78a3731e214 100644 --- a/dbtests/querytests.cpp +++ b/dbtests/querytests.cpp @@ -415,6 +415,39 @@ namespace QueryTests { checkIndex(); } }; + + class UniqueIndex : public ClientBase { + public: + ~UniqueIndex() { + client().dropCollection( "querytests.UniqueIndex" ); + } + void run() { + const char *ns = "querytests.UniqueIndex"; + client().ensureIndex( ns, BSON( "a" << 1 ), true ); + client().insert( ns, BSON( "a" << 4 << "b" << 2 ) ); + client().insert( ns, BSON( "a" << 4 << "b" << 3 ) ); + ASSERT_EQUALS( 1U, client().count( ns, BSONObj() ) ); + client().dropCollection( ns ); + client().ensureIndex( ns, BSON( "b" << 1 ), true ); + client().insert( ns, BSON( "a" << 4 << "b" << 2 ) ); + client().insert( ns, BSON( "a" << 4 << "b" << 3 ) ); + ASSERT_EQUALS( 2U, client().count( ns, BSONObj() ) ); + } + }; + + class UniqueIndexPreexistingData : public ClientBase { + public: + ~UniqueIndexPreexistingData() { + client().dropCollection( "querytests.UniqueIndexPreexistingData" ); + } + void run() { + const char *ns = "querytests.UniqueIndexPreexistingData"; + client().insert( ns, BSON( "a" << 4 << "b" << 2 ) ); + client().insert( ns, BSON( "a" << 4 << "b" << 3 ) ); + client().ensureIndex( ns, BSON( "a" << 1 ), true ); + ASSERT_EQUALS( 0U, client().count( "querytests.system.indexes", BSON( "ns" << ns ) ) ); + } + }; class All : public UnitTest::Suite { public: @@ -438,6 +471,8 @@ namespace QueryTests { add< MultiNe >(); add< EmbeddedNe >(); add< AutoResetIndexCache >(); + add< UniqueIndex >(); + add< UniqueIndexPreexistingData >(); } }; diff --git a/jstests/index8.js b/jstests/index8.js new file mode 100644 index 00000000000..8bbf01c920a --- /dev/null +++ b/jstests/index8.js @@ -0,0 +1,30 @@ +// Test key uniqueness + +t = db.jstests_index8; +t.drop(); + +t.ensureIndex( { a: 1 } ); +t.ensureIndex( { b: 1 }, true ); +t.ensureIndex( { c: 1 }, [ false, "cIndex" ] ); + +checkIndexes = function() { +// printjson( db.system.indexes.find( { ns: "test.jstests_index8" } ).toArray() ); + indexes = db.system.indexes.find( { ns: "test.jstests_index8" } ).sort( { key: 1 } ); + assert( !indexes[ 0 ].unique ); + assert( indexes[ 1 ].unique ); + assert( !indexes[ 2 ].unique ); + assert.eq( "cIndex", indexes[ 2 ].name ); +} + +checkIndexes(); + +t.reIndex(); +checkIndexes(); + +t.save( { a: 2, b: 1 } ); +t.save( { a: 2 } ); +assert.eq( 2, t.find().count() ); + +t.save( { b: 4 } ); +t.save( { b: 4 } ); +assert.eq( 3, t.find().count() ); diff --git a/mongo.xcodeproj/project.pbxproj b/mongo.xcodeproj/project.pbxproj index a109824d503..0a017643cfd 100644 --- a/mongo.xcodeproj/project.pbxproj +++ b/mongo.xcodeproj/project.pbxproj @@ -107,6 +107,7 @@ 934223C70EF16DB400608550 /* scanandorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanandorder.h; sourceTree = "<group>"; }; 934223C80EF16DB400608550 /* storage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = storage.h; sourceTree = "<group>"; }; 934223C90EF16DB400608550 /* tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tests.cpp; sourceTree = "<group>"; }; + 9343373F0F9CD6900019D5C0 /* index8.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index8.js; sourceTree = "<group>"; }; 934DD87C0EFAD23B00459CC1 /* background.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = background.cpp; sourceTree = "<group>"; }; 934DD87D0EFAD23B00459CC1 /* background.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = background.h; sourceTree = "<group>"; }; 934DD87F0EFAD23B00459CC1 /* builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builder.h; sourceTree = "<group>"; }; @@ -539,6 +540,7 @@ 93A8D1D10F37544800C92B85 /* jstests */ = { isa = PBXGroup; children = ( + 9343373F0F9CD6900019D5C0 /* index8.js */, 93AE6FB10F9631A200857F1C /* disk */, 93DCDB5B0F93ED98005349BC /* nin.js */, 9350E1220F8CFFB300B07A1C /* error2.js */, diff --git a/shell/collection.js b/shell/collection.js index 75cc0488551..36370394c61 100644 --- a/shell/collection.js +++ b/shell/collection.js @@ -141,19 +141,40 @@ DBCollection.prototype._genIndexName = function( keys ){ return name; } -DBCollection.prototype.createIndex = function( keys , name ){ +DBCollection.prototype._indexSpec = function( keys, options ) { + var name; + var unique = false; + if ( !isObject( options ) ) { + options = [ options ]; + } + for( var i = 0; i < options.length; ++i ) { + var o = options[ i ]; + if ( isString( o ) ) { + name = o; + } else if ( typeof( o ) == "boolean" ) { + unique = o; + } + } name = name || this._genIndexName( keys ); - var o = { ns : this._fullName , key : keys , name : name }; + var ret = { ns : this._fullName , key : keys , name : name }; + if ( unique == true ) { + ret.unique = true; + } + return ret; +} + +DBCollection.prototype.createIndex = function( keys , options ){ + var o = this._indexSpec( keys, options ); this._db.getCollection( "system.indexes" ).insert( o ); } -DBCollection.prototype.ensureIndex = function( keys , name ){ - name = name || this._genIndexName( keys ); +DBCollection.prototype.ensureIndex = function( keys , options ){ + var name = this._indexSpec( keys, options ).name; this._indexCache = this._indexCache || {}; if ( this._indexCache[ name ] ) return false; - this.createIndex( keys , name ); + this.createIndex( keys , options ); this._indexCache[name] = true; return true; } @@ -163,10 +184,10 @@ DBCollection.prototype.resetIndexCache = function(){ } DBCollection.prototype.reIndex = function(){ - var keys = this.getIndexKeys(); + var specs = this.getIndexSpecs(); this.dropIndexes(); - for ( var i in keys ){ - this.ensureIndex( keys[i] ); + for ( var i in specs ){ + this.ensureIndex( specs[i].key, [ specs[i].unique, specs[i].name ] ); } } @@ -213,10 +234,10 @@ DBCollection.prototype.getIndexes = function(){ return this.getDB().getCollection( "system.indexes" ).find( { ns : this.getFullName() } ); } -DBCollection.prototype.getIndexKeys = function(){ +DBCollection.prototype.getIndexSpecs = function(){ return this.getIndexes().toArray().map( function(i){ - return i.key; + return i; } ); } |