如何为Mongo中的arrary元素定义唯一索引

时间:2017-09-11 18:36:15

标签: node.js mongodb mongoose

我想为数组的最后一个元素定义一个唯一索引?甚至可能在mongo?

status[this.status.length-1].state只有user_idspecific status.state(例如有效)必须是唯一的。

注意:状态数组的最后一个元素定义了用户的当前状态。

例如:可以存在2个具有status[this.status.length-1].state: **revoked**状态的user_id。但是不能存在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"
        }
    ],

}

1 个答案:

答案 0 :(得分:2)

索引数组元素

我知道执行它的唯一方法是扭转你的问题。 最新状态应位于阵列的第一个位置。 您可以使用unshift function插入它。并以这种方式创建索引:

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);

具有部分索引的唯一索引

要使活动状态具有唯一性,您可以将先前的答案与部分索引结合使用。 部分索引将索引活动用户。

这是索引创建命令:

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\" }"
    }
})

这样,您就拥有了一个基于数组第一个元素的唯一索引。