如何为Mongo中的一个元素定义一个唯一索引
我想为数组的最后一个元素定义一个唯一索引? 这在mongo中甚至可能吗?
只有status[this.status.length-1].state
和user_id
对于specific status.state
(例如活动)必须是唯一的。
注意:状态数组的最后一个元素定义了用户的当前状态。
例如:2 user_id status[this.status.length-1].state: **revoked**
状态可以存在。 但是2个status[this.status.length-1].state: **active**
user_id不能存在。
{ "_id" : ObjectId("59a609778c6929e7122322cf"), "user_id": '9e2cZ' "status" : [ { "state" : "active", "updatedAt" : ISODate("2017-08-30T21:23:21.158Z"), "createdAt" : ISODate("2017-08-30T21:23:21.158Z") }, { "updatedAt" : ISODate("2017-08-31T22:24:02.613Z"), "createdAt" : ISODate("2017-08-31T22:24:02.613Z"), "state" : "revoked" }, { "updatedAt" : ISODate("2017-08-31T22:25:02.888Z"), "createdAt" : ISODate("2017-08-31T22:25:02.888Z"), "state" : "active" } ], }
索引一个数组元素
我知道执行它的唯一方法是扭转你的问题。 最新的状态应该在你arrays的第一位。 您可以使用不移位function来插入它。 并用这种方式创build你的索引:
db.coll.createIndex({user_id:1, 'status.0.state': 1})
这将索引数组的第一个元素。
下面是显示索引使用的解释:
db.coll.find({user_id: 1, 'status.0.state': "active"}).explain().queryPlanner.winningPlan { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "user_id" : 1, "status.0.state" : 1 }, "indexName" : "user_id_1_status.0.state_1", "isMultiKey" : false, "multiKeyPaths" : { "user_id" : [ ], "status.0.state" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "user_id" : [ "[1.0, 1.0]" ], "status.0.state" : [ "[\"active\", \"active\"]" ] } } }
要在节点中插入状态,您应该转向
user.status.push(newStatus);
成
user.status.unshift(newStatus);
具有部分索引的唯一索引
要在活动状态上具有唯一性,可以将以前的答案与部分索引结合使用。 部分索引将仅索引活动用户。
这里是索引创build命令:
db.users.createIndex( {user_id:1, 'status.0.state': 1}, {unique: true, partialFilterExpression: {"status.0.state": {$eq: 'active'}}} )
然后,我插入2个用户,一个活动,一个不活动
> db.users.find().pretty() { "_id" : ObjectId("59a609778c6929e7122322cd"), "user_id" : "9e2cZ", "status" : [ { "state" : "inactive", "updatedAt" : ISODate("2017-08-30T21:23:21.158Z"), "createdAt" : ISODate("2017-08-30T21:23:21.158Z") }, { "updatedAt" : ISODate("2017-08-31T22:24:02.613Z"), "createdAt" : ISODate("2017-08-31T22:24:02.613Z"), "state" : "revoked" }, { "updatedAt" : ISODate("2017-08-31T22:25:02.888Z"), "createdAt" : ISODate("2017-08-31T22:25:02.888Z"), "state" : "active" } ] } { "_id" : ObjectId("59a609778c6929e7122322cf"), "user_id" : "9e2cZ", "status" : [ { "state" : "active", "updatedAt" : ISODate("2017-08-30T21:23:21.158Z"), "createdAt" : ISODate("2017-08-30T21:23:21.158Z") }, { "updatedAt" : ISODate("2017-08-31T22:24:02.613Z"), "createdAt" : ISODate("2017-08-31T22:24:02.613Z"), "state" : "revoked" }, { "updatedAt" : ISODate("2017-08-31T22:25:02.888Z"), "createdAt" : ISODate("2017-08-31T22:25:02.888Z"), "state" : "active" } ] }
它的工作原理,我有2个用户具有相同的user_id但不同的状态。
如果我尝试插入另一个具有相同user_id的活动用户,则会失败:
> db.users.insert({user_id: '9e2cZ', status: [{state: 'active'}]}) WriteResult({ "nInserted" : 0, "writeError" : { "code" : 11000, "errmsg" : "E11000 duplicate key error collection: test.users index: user_id_1_status.0.state_1 dup key: { : \"9e2cZ\", : \"active\" }" } })
这样,你有一个基于数组的第一个元素的唯一索引。