Как сделать UNIQUE свойством из массива объектов на MongoDB - PullRequest
0 голосов
/ 10 июня 2019

Я пытаюсь вставить объект в массив, и у каждого объекта есть свойство с именем 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 как уникальное, но работает для других файлов, но для того же файла не работает, так как я могу создать много 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)
})

И вот ответ, который я получаю:

{
"_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

1 Ответ

0 голосов
/ 11 июня 2019

Наконец я закончил проверку на стороне 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)
    })
})
...