MongoDB,如何在集合之间使用MongoDB ObjectID?

4
使用PHP和MongoDB,我有一个名为users的集合和另一个名为forms的集合,它们在同一个数据库中。
我使用MongoDB ObjectID作为表单集合中文档的用户标识符,并将用户的ObjectID保存为每个表单文档上的uid。
我将在表单集合中创建uid字段的索引,但我的问题是我应该如何保存用户的Objectid?
目前,我将其保存为普通字符串(简化)。
$collection->insert( array('formName'=>'The name','uid'=>'CURRENT_USERS_ObjectId_AS_string') );

这是否合乎逻辑,或者在这种情况下创建一个类似于Mongodb ObjectID的uid最佳实践?
$collection->insert( array('formName'=>'The name','uid'=> new MongoId('CURRENT_USERS_ObjectId_AS_string')) );
2个回答

6

使用手动引用是可以的,甚至是推荐的。只有当它们提供特定的好处时,才使用DbRefs,例如允许自动取消引用(mongo脚本或php代码可以自动知道foo指向集合x,在数据库z中具有id y)。

不同类型是一种糟糕的设计

然而要避免类型转换。

在一个集合中实际上拥有一个外键,并且它与指向的集合的类型不同,这是一个糟糕的设计。类型转换是应该从开发中消除的东西,而不是引入的东西。

考虑数据库

在数据库上运行的代码应该能够正常工作:

form = db.forms.findOne();
user = db.users.findOne({_id: form.user_id});

不应该关心用户集合的_id字段是什么类型。有了问题中的模式,代码变成了:

form = db.forms.findOne();
user = db.users.findOne({_id: new MongoId(form.user_id)});

就其本身而言,这并不是一个巨大的区别,但这意味着您必须考虑/记住转换这些引用,并且如果/当使用不同类型的集合创建时,它会变得有问题-它会引入不一致性。

考虑以下内容:

> school = db.schools.insert({_id: 123, name: "my school"});
> userId = new ObjectId();
> db.users.insert({_id: userId, name: "Me"});
> db.forms.insert({user_id: userId, school_id: 123});

假设学校ID是一个唯一的代码。如果没有可能改变,将其作为_id字段使用是合适且明智的。现在,学校ID和用户ID是不同类型的:
> db.forms.findOne();
{
"_id" : ObjectId("508940370392baf87e68e31d"),
"user_id" : ObjectId("5089401c0392baf87e68e31b"),
"school_id" : 123
}

如果它们按原样存储,查询中仍然可能完全不知道这些不同类型的存在。
form = db.forms.findOne();
school = db.schools.findOne({_id: form.school_id});
user = db.users.findOne({_id: form.user_id});

如果使用了不同类型,那么就需要考虑“对于这个集合,我需要将字符串转换为ObjectId,但对于另一个集合,我不能这样做”。这是一个本可以避免却被引入的问题。

1
非常好的观点,在非常好的答案中!在这种情况下,我将坚持将密钥存储为字符串,而不是ObjectId,因为我不确定如果表单集合中的uid字段是ObjectId类型,索引该字段是否会像字符串类型那样好。对此有什么想法吗?指数的后果。 - Henkealg
2
这个问题已经有了现成的答案。对象ID更小,因此比较速度更快。 - AD7six
1
是的,关于类型转换的观点很好。让我看看能否清理我的模式设计。谢谢 :) - Akshat Jiwan Sharma
@AD7six 对不起,我再跟进一下。只是为了确认一下。根据我问题中的示例,您会选择替代方案2,在存储uid时使用new Mongoid(),而不是字符串吗?谢谢。 - Henkealg
是的,请将 forms.uid 存储为与 users._id 完全相同。 - AD7six

4

我对PHP不太熟悉,但你提出的模式设计很好。我在我的C#实现中使用了类似的结构。为了明确起见,这是我的模式设计样例:

Account Class

public  ObjectId Id{get;set;}
public   string  Email {get;set}
public   string  Password{get;set;}

User Class

 public ObjectId Id{get;set;} 
 public string  AccountId {get;set}//refers to the ID in the account.

现在,如果我想查询任何用户的帐户,我可以简单地在用户类中使用accountId进行查询。
MongoDB将这种引用技术称为手动引用,并且这也是它建议的引用方式。这是链接:http://docs.mongodb.org/manual/applications/database-references/

1
感谢您的好答案。我正在寻找类似于上面发布的答案中的MongoDB信息,但没有找到。我将采用备选方案,使用普通索引,因为这是您和供应商在文章中建议的。 - Henkealg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接