MongoDB 架构:将 id 存储为 FK 或整个文档
MongoDB schema: store id as FK or whole document
我正在设计 MongoDB 结构(实际上是 NodeJS 应用程序中的模型结构)。我会有 玩家 和 比赛 collections。
是只存储玩家参加的比赛的 ID,在每个玩家的 object 中(就像 RDBM 中的 FK)还是在玩家 object 中存储整个比赛 object =27=]?
在应用程序中,其中一项操作是显示比赛的详细信息,在此视图中,用户将看到参加该特定比赛的球员(他们的姓名、国家/地区等)。这让我认为将整个 Match
文档存储在 Player
文档中更好。
有什么建议吗?
在我看来,这里的matches集合是一个独立存在的文档集合,然后与参加比赛的玩家联系起来。话虽如此,我会做一个匹配键数组。
如果被嵌套的文档可以被父文档视为 "owned",我建议使用嵌套文档结构。例如,todo 嵌套文档位于 todoList 文档中。
我认为将整个 Match 文档存储在 Player 文档中不是一个好的选择。
每次球员参加比赛时,您的球员文件都需要更新。
您有 2 个主要选择:
1-) 使用子引用。 (引用比赛中的球员)。
所以如果我们想使用 mongoose 模型来实现它:
球员模型:
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 的):
{
"_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-) 将玩家嵌入比赛中,并仍然保持独立的玩家集合。
但这将比第一个选项需要更多 space。
因此您的匹配项在匹配项集合中将如下所示:
{
"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);
});
这是一个多对多关系的例子。
我猜最初会有大约 100 名球员和 100 场比赛的数据。
设计选项是 embedding 或 referencing.
(1) 嵌入:
查询最多的一面将嵌入查询较少的一面。
根据您的要求(显示比赛的详细信息,在此视图中,用户将看到参加此特定比赛的球员及其详细信息)比赛方将嵌入球员数据。
结果是两个 collections.The 主要的是比赛。次要的是玩家;这将包含玩家的所有源数据(id、姓名、dob、国家和其他详细信息)。
一场比赛只存储了少数球员数据,比赛集合中只存储了球员数据的一个子集。
导致播放器数据重复。这很好,它主要是将被复制的静态信息;名字和国家之类的东西。但是,随着时间的推移,其中一些可能需要更新,应用程序需要处理这个问题。
玩家数据存储为 matches 集合中的嵌入文档数组。 此设计是可能的解决方案。
匹配项:
_id
matchId
date
place
players [ { playerId 1, name1, country1 }, { playerId 2, ... }, ... ]
outcome
玩家:
_id
name
dob
country
ranking
(2) 引用:
这也将有两个集合:球员和比赛。
参考可以发生在任何一方,比赛可以参考球员,反之亦然。
根据需求,查询最多的一侧将有查询较少的一侧的引用;比赛将有玩家 ID 参考。这将是一组玩家 ID。
匹配项:
_id
matchId
date
place
players [ playerId 1, playerId 2, ... ]
players 集合将具有与之前情况相同的数据。
我正在设计 MongoDB 结构(实际上是 NodeJS 应用程序中的模型结构)。我会有 玩家 和 比赛 collections。
是只存储玩家参加的比赛的 ID,在每个玩家的 object 中(就像 RDBM 中的 FK)还是在玩家 object 中存储整个比赛 object =27=]?
在应用程序中,其中一项操作是显示比赛的详细信息,在此视图中,用户将看到参加该特定比赛的球员(他们的姓名、国家/地区等)。这让我认为将整个 Match
文档存储在 Player
文档中更好。
有什么建议吗?
在我看来,这里的matches集合是一个独立存在的文档集合,然后与参加比赛的玩家联系起来。话虽如此,我会做一个匹配键数组。
如果被嵌套的文档可以被父文档视为 "owned",我建议使用嵌套文档结构。例如,todo 嵌套文档位于 todoList 文档中。
我认为将整个 Match 文档存储在 Player 文档中不是一个好的选择。 每次球员参加比赛时,您的球员文件都需要更新。
您有 2 个主要选择:
1-) 使用子引用。 (引用比赛中的球员)。
所以如果我们想使用 mongoose 模型来实现它:
球员模型:
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 的):
{
"_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-) 将玩家嵌入比赛中,并仍然保持独立的玩家集合。 但这将比第一个选项需要更多 space。
因此您的匹配项在匹配项集合中将如下所示:
{
"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);
});
这是一个多对多关系的例子。 我猜最初会有大约 100 名球员和 100 场比赛的数据。 设计选项是 embedding 或 referencing.
(1) 嵌入:
查询最多的一面将嵌入查询较少的一面。 根据您的要求(显示比赛的详细信息,在此视图中,用户将看到参加此特定比赛的球员及其详细信息)比赛方将嵌入球员数据。
结果是两个 collections.The 主要的是比赛。次要的是玩家;这将包含玩家的所有源数据(id、姓名、dob、国家和其他详细信息)。
一场比赛只存储了少数球员数据,比赛集合中只存储了球员数据的一个子集。 导致播放器数据重复。这很好,它主要是将被复制的静态信息;名字和国家之类的东西。但是,随着时间的推移,其中一些可能需要更新,应用程序需要处理这个问题。
玩家数据存储为 matches 集合中的嵌入文档数组。 此设计是可能的解决方案。
匹配项:
_id
matchId
date
place
players [ { playerId 1, name1, country1 }, { playerId 2, ... }, ... ]
outcome
玩家:
_id
name
dob
country
ranking
(2) 引用:
这也将有两个集合:球员和比赛。 参考可以发生在任何一方,比赛可以参考球员,反之亦然。 根据需求,查询最多的一侧将有查询较少的一侧的引用;比赛将有玩家 ID 参考。这将是一组玩家 ID。
匹配项:
_id
matchId
date
place
players [ playerId 1, playerId 2, ... ]
players 集合将具有与之前情况相同的数据。