Схема MongoDB: хранить идентификатор как FK или весь документ - PullRequest
1 голос
/ 07 ноября 2019

Я проектирую структуру MongoDB (на самом деле структуру моделей в приложении NodeJS). У меня будет игроков и матчей коллекций.

Лучше ли хранить только идентификаторы совпадений, к которым присоединился игрок, внутри объекта каждого игрока (например, FK в RDBM) или хранить весь объект совпадения внутри объекта игрока?

В приложении одним из действий будет показ подробностей матча, и в этом представлении пользователь увидит игроков, которые присоединились к этому конкретному матчу (их имена, страна и т. Д.). Это заставляет меня думать, что лучше хранить весь документ Match внутри документа Player.

Любые советы?

Ответы [ 3 ]

2 голосов
/ 07 ноября 2019

Хранение всего документа Match внутри документа Player, я думаю, не очень хороший вариант. Ваш документ игрока должен обновляться каждый раз, когда игрок играет в матче.

У вас есть 2 основных варианта:

1-) Использование дочерних ссылок. (ссылка на игрока в матче).

Итак, если мы хотим реализовать это, используя модели мангустов:

Модель игрока:

const mongoose = require("mongoose");

const playerSchema = mongoose.Schema({
  name: String,
  country: String
});

const Player = mongoose.model("Player", playerSchema);

module.exports = Player;

Модель матча:

const mongoose = require("mongoose");

const matchSchema = mongoose.Schema({
  date: {
    type: Date,
    default: Date.now()
  },
  players: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Player"
    }
  ]
});

const Match = mongoose.model("Match", matchSchema);

module.exports = Match;

С этими моделями наш документ матча будет выглядеть следующим образом (со ссылкой на playerId's):

{
    "_id" : ObjectId("5dc419eff6ba790f4404fd07"),
    "date" : ISODate("2019-11-07T16:19:39.691+03:00"),
    "players" : [
        ObjectId("5dc41836985aaa22c0c4d423"),
        ObjectId("5dc41847985aaa22c0c4d424"),
        ObjectId("5dc4184e985aaa22c0c4d425")
    ],
    "__v" : 0
}

И мы можем использовать этот маршрут для получения информации о матче со всей информацией об игроках:

const Match = require("../models/match");


router.get("/match/:id", async (req, res) => {
  const match = await Match.findById(req.params.id).populate("players");

  res.send(match);
});

И результат будет таким:

[
    {
        "date": "2019-11-07T13:19:39.691Z",
        "players": [
            {
                "_id": "5dc41836985aaa22c0c4d423",
                "name": "player 1",
                "country": "country 1",
                "__v": 0
            },
            {
                "_id": "5dc41847985aaa22c0c4d424",
                "name": "player 2",
                "country": "country 1",
                "__v": 0
            },
            {
                "_id": "5dc4184e985aaa22c0c4d425",
                "name": "player 3",
                "country": "country 2",
                "__v": 0
            }
        ],
        "_id": "5dc419eff6ba790f4404fd07",
        "__v": 0
    }
]

2-) Встраивание игроков в матч и сохранение независимой коллекции игроков. Но для этого потребуется больше места, чем для первого варианта.

Таким образом, ваше совпадение будет выглядеть так в коллекции совпадений:

    {
        "date": "2019-11-07T13:19:39.691Z",
        "players": [
            {
                "_id": "5dc41836985aaa22c0c4d423",
                "name": "player 1",
                "country": "country 1",
                "__v": 0
            },
            {
                "_id": "5dc41847985aaa22c0c4d424",
                "name": "player 2",
                "country": "country 1",
                "__v": 0
            },
            {
                "_id": "5dc4184e985aaa22c0c4d425",
                "name": "player 3",
                "country": "country 2",
                "__v": 0
            }
        ],
        "_id": "5dc419eff6ba790f4404fd07",
        "__v": 0
    }

Но это может быть немного быстрее при получении информации о совпадении,так как нет необходимости заполнять информацию об игроках.

const Match = require("../models/match");

router.get("/match/:id", async (req, res) => {
  const match = await Match.findById(req.params.id);

  res.send(match);
});
1 голос
/ 07 ноября 2019

На мой взгляд, коллекция соответствует здесь представляет собой набор документов, которые существуют независимо, а затем связаны с игроками, участвующими в матчах. С учетом сказанного, я бы сделал массив ключей сопоставления .

. Я бы предложил использовать структуру вложенного документа, если вложенный документ может рассматриваться как "принадлежащий" родительскому документу. ,Например, вложенный документ todo внутри документа todoList .

0 голосов
/ 07 ноября 2019

Это случай отношения многих ко многим. Я предполагаю, что изначально будет около 100 игроков и 100 матчей. Варианты дизайна: встраивание или , ссылающиеся .

(1) Вложение:

Наиболее запрашиваемая сторона будет иметьменее запрошенная сторона встроена. В зависимости от вашего требования (показать детали матча, и в этом представлении пользователь увидит игроков, которые присоединились к этому конкретному матчу, и их данные) на стороне матча будут вставлены данные игрока.

В результате получится дваКоллекции. Основной - спички. Второстепенные игроки;здесь будут все исходные данные для игрока (идентификатор, имя, название, страна и другие данные).

Для матча сохраняются только данные нескольких игроков, и только подмножество данных игрокахранится в коллекции матчей. Результатом является дублирование данных игрока. Это хорошо, это в основном статическая информация, которая будет дублироваться;такие вещи, как имя и страна. Но некоторые из них могут нуждаться в обновлениях с течением времени, и приложение должно позаботиться об этом.

Данные проигрывателя хранятся в виде массива встроенных документов в коллекции совпадений. Этот дизайн является возможным решением.

совпадений:

_id
matchId
date
place
players [ { playerId 1, name1, country1 }, { playerId 2, ... }, ... ]
outcome

игроков:

_id
name
dob
country
ranking


(2) Ссылка:

Это также будет иметь две коллекции: игроки и матчи. Ссылки могут происходить с любой стороны, матчи могут ссылаться на игроков или наоборот. Исходя из требования, наиболее запрашиваемая сторона будет иметь ссылки на менее запрашиваемую сторону;совпадения будут иметь ссылки на идентификаторы игроков. Это будет массив идентификаторов игроков.

совпадений:

_id
matchId
date
place
players [ playerId 1, playerId 2, ... ]

Коллекция Players будет иметь те же данные, что и в предыдущем случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...