3

我目前正在尝试弄清楚 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)?

4

3 回答 3

5

First of all there are no relations and joins in mongodb. All 'relations' are logical, but it not real relation like in sql database. In test above you storing person twice: first person goes into persons collection, second i guess goes into nested collection of persons within group.

You just duplicated person. So, they are not related. And if person was updated in persons collection it does not mean that he will magically updated in nested collection of persons within group collection. This is the reason why your test fails.

Usual one to many relation in mongodb good fit for embedding.

Update: I guess you have documents like this:

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);
    }
}

Also i a little modified your test to get it work:

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); 
于 2011-04-12T21:44:27.353 回答
4

没有相关集合的关系或自动更新之类的东西。似乎您希望 mongo 表现得像 ORM,但这不是它的作用,至少不是 C# 驱动程序。如果你想保存一个人和一个组,你必须分别保存它们。

与其在组对象中存储完整的人员对象,不如只存储人员 ID。然后在需要人员数据时使用这些 ID 来查找人员。

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

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

于 2011-04-14T16:21:23.797 回答
3

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

您使用插入而不是更新保存,因此它将为您创建一个新文档。

于 2011-04-12T21:21:22.743 回答