【问题标题】:How to make UNIQUE a property from an array of objects on MongoDB如何从 MongoDB 上的对象数组中创建 UNIQUE 属性
【发布时间】:2019-06-11 05:21:29
【问题描述】:

我正在尝试将一个对象推送到一个数组中,并且每个对象都有一个名为 name 的属性,该属性应该是唯一的

这是我的 mongodb 架构:

db.createCollection("users", {
   validator: {
      $jsonSchema: {
         bsonType: "object",
         required: ["nickname", "email", "password", "salt"],
         properties: {
            nickname: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            password: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            email: {
               pattern: "^[^@\s]+@[^@\s]+\.[^@\.\s]+$",
               bsonType: "string",
               description: "must be a valid email and is required"
            },
            salt: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            characters: {
               bsonType: "array",
               required: [
                  "name",
                  "head",
                  "class",
                  "race",
                  "genre",
                  "agility",
                  "charisma",
                  "constitution",
                  "inteligence",
                  "strength",
                  "level"
               ],
               properties: {
                  name: {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },
                  description: {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },
                  head: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  class: {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },
                  race: {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },
                  genre: {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },
                  agility: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  charisma: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  constitution: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  intelligence: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  strength: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  "time-online": {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  gold: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  level: {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  "experience-obtained": {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  "experience-for-next-level": {
                     bsonType: "int",
                     description: "must be a integer and is required"
                  },
                  online: {
                     type: "boolean",
                     description: "must be a boolean and is required"
                  },
                  "home-town": {
                     bsonType: "string",
                     description: "must be a string and is required"
                  },

                  items: {
                     bsonType: "array",
                     required: ["id", "quantity"],
                     properties: {
                        "id": {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        },
                        "quantity": {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        }
                     }
                  },

                  position: {
                     bsonType: "object",
                     required: ["position-x", "position-y", "map"],
                     properties: {
                        "position-x": {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        },
                        "position-y": {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        },
                        "map": {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        }
                     }
                  },

                  deaths: {
                     bsonType: "object",
                     required: ['characters', 'npcs'],
                     properties: {
                        characters: {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        },
                        npcs: {
                           bsonType: "int",
                           description: "must be a integer and is required"
                        }
                     }
                  }

               }
            }
         }
      }
   }
})

db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ nickname: 1 }, { unique: true })
db.users.createIndex({ "characters.name": 1 }, { unique: true })

正如您在最后一行中看到的那样,我正在尝试将 characters.name 设置为唯一但适用于其他文件,但对于同一个文件不起作用,因为我可以创建许多 @ 987654326@同名

这是我的操作(我用mongojs

mongodb.users.findAndModify({
    query: { 
        email: req.body.email, 
    },
    update: { 
        $push: { characters: newCharacter } 
    },
    new: true
}, function (error, user, lastErrorObject) {
    if (error) return res.status(500).json(error)

    if (!user) {
        return res.status(500).send("No existe el usuario con el email: " + req.body.email)
    }

    console.info("Se creo un nuevo personaje con el nombre: " + req.body.name)
    return res.status(200).json(user)
})

这是我得到的回应:

{
"_id": "5cfda33d0c1ceea5196afd93",
"nickname": "juancito2",
"password": "4e523cf0d1ff0cc6a372e22d04b7735efbcf01a19bca1843ac6b9046e8b62108",
"email": "a@a.a2",
"salt": "kZFsK0s+ehyXA9GOWn+ehw==",
"characters": [
    {
        "name": "recox1",
        "description": "un pj poderoso",
        "head": 1,
        "class": "Warrior",
        "race": "Elf",
        "genre": "Male",
        "agility": 10,
        "charisma": 11,
        "constitution": 12,
        "intelligence": 13,
        "strength": 14,
        "gold": 200,
        "level": 1
    },
    {
        "name": "recox1",
        "description": "un pj poderoso",
        "head": 1,
        "class": "Warrior",
        "race": "Elf",
        "genre": "Male",
        "agility": 10,
        "charisma": 11,
        "constitution": 12,
        "intelligence": 13,
        "strength": 14,
        "gold": 200,
        "level": 1
    },
}

我做错了什么?我需要做什么来实现我的目标?我阅读了这些文件,但没有运气。

https://docs.mongodb.com/manual/core/index-unique/

https://docs.mongodb.com/manual/core/index-compound/#index-type-compound

https://docs.mongodb.com/manual/core/index-multikey/#multikey-indexes

【问题讨论】:

  • 你能检查索引是用unique 选项使用db.users.getIndexes() 创建的吗?使用db.users.createIndex({ "characters.name": 1 }, { unique: true }) 将您的问题减少到最少的复制,我无法插入多个同名字符。例如:db.users.insert({characters: { name: 'Bobby' }}).
  • 据我所知,我们可以为同一个文件设置唯一索引,与其他用户一起工作正常,就像你上面提到的那样。现在我想弄清楚如何才能确保我在数组中有一个具有属性名称的对象
  • 请编辑您的问题以包含一个未按预期验证的示例文档以及您尝试运行的插入或更新操作。
  • @Stennie 完成,我修改了问题
  • 谢谢 - 示例文档非常有帮助。唯一索引约束适用于separate documents in the collection,因此这确实允许在同一文档中的数组内重复。对于您当前的架构,我不确定服务器是否有一种直接的方法来评估嵌入式数组中单个字段的唯一性,因此您可能必须在客户端逻辑中进行评估或使用单独的字符集合。

标签: arrays mongodb mongojs


【解决方案1】:

最后我最终在client 端进行验证,因为 mongodb 不允许同一文件的数组中唯一,如果将来有人看到更好的方法,我会很高兴

    //As in MongoDB we can't or i don't know how to perform this in one action
//First we do a query to get the user account and then I check if there is an user with that name in the account
//Then we perform a second query to save the character in case it doesn't exist
//Because if I don't do this verification I can repeate the character.name inside the user
//Even if "characters.name" is an index.

mongodb.users.findOne({
    email: req.body.email
}, function (error, user) {
    if (error) return res.status(500).json(error)
    if (!user) return res.status(409).send("No existe un usuario con el email: " + req.body.email)

    //Verify if the character.name is already in the user account
    if (user && user.characters) {
        const isCharacterInUser = user.characters.find(el => el.name === req.body.name);
        if (isCharacterInUser) return res.status(409).send("Ya existe un personaje con ese nombre en esta cuenta " + req.body.name)
    }

    //If the account does not have any character, initalize the array
    user.characters = user.characters ? user.characters : [];

    user.characters.push(newCharacter)
    mongodb.users.save(user, function(error, doc) {
        if (error && error.code === 11000) return res.status(409).send("Ya existe un personaje con ese nombre")
        if (error) return res.status(500).json(error)

        return res.status(200).json(doc)
    })
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    相关资源
    最近更新 更多