2011-04-12 28 views
3

我目前正试图弄清楚,Nosql数据库如何处理关系以及文档的唯一标识真正意味着什么。独特性在NoSQL世界中意味着什么,我如何处理MongoDB中的关系?

也许我期待太多的MongoDb,或者我还没有掌握NoSQL数据库关系的概念。

基本上,下面的测试失败,我不知道如何模拟用户和组之间的这种关系(这是1:0..N关系)。

[TestFixture] 
public class MongoDbExamples 
{ 

    private MongoServer _mongoServer; 

    [TestFixtureSetUp] 
    public void FixtureSetUp() 
    { 
     _mongoServer = MongoServer.Create(); 
    } 

    [TestFixtureTearDown] 
    public void FixtureTearDown() 
    { 
     _mongoServer.Disconnect(); 
    } 


    [Test] 
    public void RelationTest() 
    { 
     var database = _mongoServer.GetDatabase("StackoverflowExamples"); 

     var p = new Person() { Name = "Testperson" }; 
     var persons = database.GetCollection<Person>("Persons"); 
     persons.Save<Person>(p); 

     var group = new Group() { Description = "A fancy descriptor" }; 
     group.Add(p); 
     var groups = database.GetCollection<Group>("Groups"); 
     groups.Save<Group>(group); 

     var readPerson = persons.FindOneById(p.Id); 
     readPerson.Name = "a different name"; 
     // since the id hasn't change this is an update of the original person: 
     persons.Insert<Person>(readPerson); 

     // and I thought that it should be reflected in the group as well: 
     var readGroup = groups.FindOneById(group.Id); 
     Assert.AreEqual(readPerson.Id, readGroup.persons[0].Id); // this passes, the id is the same 
     Assert.AreEqual(readPerson.Name, readGroup.persons[0].Name); // this fails, the groups person still has the old name 
    } 

} 

是这种关系存在的最佳实践?例如。应该搜索所有收藏夹/文档中的所有人,并将找到的人与收集人的匹配人交换?或者是NoSQL数据库不擅长的关系,我应该避免关系(我想知道如何在具有更复杂对象图的更大系统中使用NoSQL-DB)?

回答

4

有没有这样的事情关系或自动更新相关集合。似乎你希望mongo的行为像一个ORM,但这不是它的作用,至少不是用C#驱动程序。如果你想保存一个人和一个组,你将不得不单独保存它们。

而不是在组对象中存储完整的人员对象,而应该只存储人员ID。然后,在需要人员数据时,使用这些ID查找该人员。

此外,您可能会阅读dbref上的文档。

http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef

+0

+1链接。我想我终于明白了NoSQL数据库的概念。此外,DBRef关键字似乎是我需要的(“ 使用DBRef类。它将集合名称和_id作为参数传递给构造函数,然后可以使用Database类的FollowReference方法来获取引用的文档。”)为了读取目的,我需要手动更新Andrew Orsich指出的实体。 – tobsen 2011-04-15 06:06:21

3

除非您为其创建唯一索引,否则名称上没有唯一性。 (见http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes

您使用插入,而不是更新保存所以它会为你创建一个新文档。

+0

即使我使用的保存,还有两个不同的人用相同的ID:一个人收集,一个嵌在一组。有没有一种方法可以实现我想要做的事情(拥有一个“全球唯一”的人,只有在其他文档中没有必要嵌入引用的人)?我不明白这些独特的索引,你能否提供一个工作示例(例如,修改上面的代码)? – tobsen 2011-04-12 21:57:03

+1

也看看这个页面:http://www.mongodb.org/display/DOCS/Database+References – 2011-04-12 22:54:23

5

首先在mongodb中没有关系和连接。所有'关系'都是合乎逻辑的,但它不像sql数据库中的那种真正的关系。在上面的测试中,你存储了两次人物:第一个人进入人物收集,第二个人进入组内人物的嵌套收集。

你刚刚复制人。所以,他们没有关系。如果更新了人员收集,并不意味着他将神奇地更新组内收集的人员。这就是你的测试失败的原因。

mongodb中的一对多关系很适合嵌入。

更新: 我想你有这样的文件:

public class Person 
{ 
    public Person() 
    { 
     Id = ObjectId.GenerateNewId().ToString(); 
    } 

    [BsonId] 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

public class Group 
{ 
    public Group() 
    { 
     Id = ObjectId.GenerateNewId().ToString(); 
     persons = new List<Person>(); 
    } 

    [BsonId] 
    public string Id { get; set; } 
    public string Description { get; set; } 

    public List<Person> persons { get; set; } 

    public void Add(Person p) 
    { 
     persons.Add(p); 
    } 
} 

而且IA小修改了测试,以得到它的工作:

var database = _mongoServer.GetDatabase("StackoverflowExamples"); 

var p = new Person() { Name = "Testperson" }; 
var persons = database.GetCollection<Person>("Persons"); 
persons.Save<Person>(p); 

var group = new Group() { Description = "A fancy descriptor" }; 
group.Add(p); 
var groups = database.GetCollection<Group>("Groups"); 
groups.Save<Group>(group); 

//Groups collection 
//{ 
// "_id": "4da54d3c00a9ec06a0067456", 
// "Description": "A fancy descriptor", 
// "persons": [ 
// { 
//  "_id": "4da54d3b00a9ec06a0067455", 
//  "Name": "Testperson" 
// } 
// ] 
//} 

//Persons collection 
//{ 
// "_id": "4da54d3b00a9ec06a0067455", 
// "Name": "Testperson" 
//} 


var readPerson = persons.FindOneById(p.Id); 
readPerson.Name = "a different name"; 
//Here i've changed Insert to Save 
persons.Save(readPerson); 

//Here you updating person in persons collection, 
//but within group name still old 

//Persons collection 
//{ 
// "_id": "4da54d3b00a9ec06a0067455", 
// "Name": "a different name" 
//} 

//So to achieve 'physical relation' you need also update person within group 
var query = Query.EQ("persons._id", readPerson.Id); 
groups.Update(query, Update.Set("persons.$.Name", readPerson.Name)); 

//Groups collection 
//{ 
// "_id": "4da54d3c00a9ec06a0067456", 
// "Description": "A fancy descriptor", 
// "persons": [ 
// { 
//  "_id": "4da54d3b00a9ec06a0067455", 
//  "Name": "a different name" 
// } 
// ] 
//} 


//Test passed 
var readGroup = groups.FindOneById(group.Id); 
Assert.AreEqual(readPerson.Id, readGroup.persons[0].Id); 
Assert.AreEqual(readPerson.Name, readGroup.persons[0].Name); 
+1

那么我怎样才能实现一种“物理关系”呢?在这个例子中,我是否必须坚持集合中的人并将其嵌入集合集合中,并且在阅读之后,搜索该人员并手动交换它? – tobsen 2011-04-12 21:54:56

+1

@tobsen:我已经更新了我的答案。 – 2011-04-13 07:23:13

+0

(+1)感谢Andrew澄清更新程序。然而,链接sym3tri和高科技提供的最终让我明白。 – tobsen 2011-04-15 06:05:46