我是mongodb的新手,请看one-to-many example
根据我的理解
这个例子说一个人可以写一个故事或一个故事belongs_to
一个人,我认为将person._id
存储在故事集中就足够了
为什么个人收藏集有field
stories
获取数据的案例
案例1
获取身份证明为x
解决方案:为此,只需触发故事集where
author = x
案例2
获取特定故事的author name
解决方案:为此我们有author
字段故事集
答案 0 :(得分:1)
简单地说:因为在MongoDB中没有明确的关系这样的概念。
猫鼬不知道你想如何解决这段关系。搜索是来自给定的故事对象,作者是否会找到?或者搜索是否会找到作者对象的所有故事?所以它确保它可以解决这种关系。
请注意,该方法存在问题,大存在问题。假设我们不是在谈论这个例子中的一对一关系,而是一个与一对一的Shitload"™关系。自BSON documents have a size limit of 16MB以来,您可以通过这种方式管理关系。相当一些,但会有一个人为限制。
如何解决这个问题:不要使用ODM,而是自己进行正确的建模。既然你知道你的用例。我将在下面举例说明。
让我们先详细说明你的案例:
好的,现在让我们把mongoose放在一边,让我们考虑一下如何自己实现它。记住
MongoDB中的数据建模是从您的用例问题中推导出您的模型,以便以最有效的方式覆盖最常见的用例。
与RDBMS建模相反,在这里你可以识别你的实体,它们的属性和关系,然后跳过一些环节来解决你的问题以某种方式。
所以,看看我们的用户故事,我想我们可以同意2是最常见的用例,3和1接下来,4与其他用例相比是相当罕见的。
现在我们可以开始了
我们首先对最常见用例中涉及的数据进行建模。
因此,我们希望使故事查询最有效。我们希望按照提交的降序对故事进行排序。很简单:
{
_id: new ObjectId(),
user: "Name to Display",
story: "long story cut short",
}
现在假设你想要展示你的故事,其中10个:
db.stories.find({}).sort({_id:-1}).limit(10)
没有关系,我们需要的所有数据,单个查询,都使用default index on _id
进行排序。由于timestamp is part of the ObjectId并且它是最重要的部分,我们可以使用它来按时间对故事进行排序。问题"嘿,但如果改变他或她的用户名怎么办?"通常现在来了。简单:
db.stories.update({"user":oldname},{$set:{"user":newname}},{multi:true})
由于这是一个罕见的用例,它只需要是可行的,而且不必非常有效。但是,稍后我们将看到我们必须在user
上建立一个索引。
谈论作者:这真的取决于你想要怎么做。但我会告诉你我是如何建模的:
{
_id: "username",
info1: "foo",
info2: "bar",
active: true,
...
}
我们在这里使用_id
的一些属性:它是具有唯一约束的必需索引。正是我们想要的用户名。
然而,它有一个警告:_id
is immutable。因此,如果有人想要更改其用户名,我们需要将原始用户复制到包含新用户名_id
的文档,并相应地更改我们故事中的用户属性。这种方式的优点是,即使更改用户名(见上文)的更新在运行时期间失败,每个故事仍然可以与用户相关。如果更新成功,我倾向于注销用户并让他再次使用新用户名登录。
如果您想区分用户名和显示的名称,这一切都变得更加容易:
{
_id: "username",
displayNames: ["Foo B. Baz","P.S. Eudonym"],
...
}
然后你在故事中使用显示名称。
现在让我们看看如何获取给定故事的用户详细信息。我们知道作者的名字,所以它很简单:
db.authors.find({"_id":authorNameOfStory})
或
db.authors.find({"displayNames": authorNameOfStory})
查找给定用户的所有故事也非常简单。它是:
db.stories.find({"name":idFieldOfUser})
或
db.stories.find({"name":{$in:displayNamesOfUser}})
现在我们已经涵盖了所有用例,现在我们可以通过
提高效率故事模型user
字段中有一个明显的索引,所以我们这样做:
db.stories.ensureIndex({"name":1})
如果您使用"用户名为_id
"只有这样,你完成了索引。使用显示名称,您显然需要索引它们。由于您最有可能希望显示名称和假名是唯一的,因此它有点复杂:
db.authors.ensureIndex({"displayNames":1},{sparse:true, unique:true})
注意:我们需要将其设为sparse index,以便在有人尚未决定使用显示名称或假名时防止出现不必要的错误。确保仅在用户决定显示名称时,才将添加此字段显式添加到作者文档中。否则,它会评估到null
服务器端, 是一个有效值,而将得到一个约束违规错误,即" E1100重复密钥& #34;
我们已经涵盖了应用程序处理的所有用例,从而大大简化了我们的数据模型,并为最常见的用例提供了最有效的查询。考虑到我们在进行查询时已经拥有的信息,每个用例都包含在一个查询中。
请注意,由于我们使用隐式关系,因此用户可以发布多少故事没有人为限制。
对于更复杂的查询("每个用户每月提交多少个故事?"),请使用aggregation framework。这就是它的用途。