如何从MongoDB上的一系列对象中使UNIQUE成为属性

时间:2019-06-10 00:42:11

标签: arrays mongodb mongojs

我正在尝试将一个对象推入数组,并且每个对象都有一个名为 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 设置为唯一,但适用于其他文件,但是对于同一文件却无法使用,因为我可以创建许多{ {1}}同名

这是我的手术(我使用characters

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

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

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

1 个答案:

答案 0 :(得分:0)

最后,我最终在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)
    })
})