NoSQL世界中的唯一性是什么意思,我如何处理MongoDB中的关系?

时间:2011-04-12 21:13:03

标签: c# mongodb mongodb-.net-driver nosql

我目前正在试图弄清楚,Nosql数据库如何处理关系以及文档的唯一ID真正意味着什么。

也许我对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,然后使用更复杂的对象图)?

3 个答案:

答案 0 :(得分: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);
    }
}

我也稍微修改了你的测试以使其工作:

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 :(得分:4)

没有相关集合的关系或自动更新之类的东西。好像你希望mongo表现得像ORM,但这不是它的作用,至少不是C#驱动程序。如果要保存人员和组,则必须单独保存。

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

另外,您可能想阅读dbref上的文档。

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

答案 2 :(得分:3)

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

您使用插入代替更新保存,以便为您创建新文档。