【问题标题】:MongoDB : Use string instead of BsonObjectIdMongoDB:使用字符串而不是 BsonObjectId
【发布时间】:2015-04-13 18:10:18
【问题描述】:

我的游戏有一个 REST 服务,并决定尝试 MongoDB - 除了“_id”字段要求之外,这似乎很简单。

这里的问题是我的客户端应用程序正在使用 REST 服务,并且不知道“mongodb”、它的驱动程序或依赖项——也不应该。为了将客户端与服务器端(REST 服务提供者)分离,我需要解决 MongoDB 似乎需要 BsonObjectId 类型的“_id”字段这一事实。

目前我使用的是轻量级 DAO 层,所以不用:

using System;

public class Item {
     private BsonObjectId _id;
     private string name;
}

我正在使用 DAO 将其转换为“mongodb 不可知论”:

using System;

public class ItemDAO {
     private string _id;
     private string name;
}

理想情况下,完全摆脱 BsonObjectId 会很好 - 是否有一些可以使用的注释/自定义序列化处理程序或者我能够使用字符串而不是 BsonObjectId 的某种方式?

如果做不到这一点,有什么方法可以让 MongoDB 包装对象,以便用 _id 装饰它们,我可以将其作为字符串注入行中?

理想的结果是根本没有 DAO 类,只有“Item”,并让 Item 使用字符串作为 _id(或不需要 mongodb 依赖项即可融入客户端实现的东西)。

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    您的文档必须有一个 _id 字段,但它不必是 ObjectID。唯一的要求是它对集合来说是唯一的。

    如果您在保存新文档时不提供 _id 字段,MongoDB 将为您生成一个 ObjectId,但这只是一个辅助函数。

    【讨论】:

    • 帮助很大 - 谢谢大家!这就是我的答案,因为这个 mongodb 实例将支持相对低容量的数据问题(游戏匹配服务器注册)。
    【解决方案2】:

    如果您不想“污染”您的模型分类,您可以在数据访问代码中注册适当的 Id 生成器。

    BsonSerializer.RegisterIdGenerator(typeof(string), new StringObjectIdGenerator());
    

    这样您的模型中将有 String 字段,但在其下方将是 ObjectId,这很不错,即您可以看到添加记录的时间(大约)

    但是,如果您决定在 REST 服务中接受来自客户端的 Id(通过 PUT),那么 ObjectId 显然不是可行的方法。

    看看这个article,因为它描述了如何设置序列化选项等。

    【讨论】:

      【解决方案3】:

      如何查询对象?如果您不希望/不需要客户端中的 _id 字段,可以使用 projection 从结果中排除 _id 字段。

      另外,请注意,生成您自己的基于字符串的 _id 可能会对数据库大小产生严重影响。 ObjectId 似乎是一个非常有效的结构。我已经尝试使用字符串作为 _id,以避免在我永远不会使用的字段上创建索引 - 但在我的情况下,数据库大小的成本使其不可行。当然,这取决于您的数据库大小和其余内容。

      【讨论】:

        【解决方案4】:

        将 BSON ObjectIds 表示为字符串是司空见惯的;默认情况下,Mongo 驱动程序将生成 96 位 ID,然后您显然可以将其表示为 24 个十六进制字节。大多数客户端库都具有从字符串创建ObjectIds 并将它们转换为字符串的功能。

        您将让您的外部接口将_id 视为一个字符串,然后当您的Mongo-aware DB 层接收一个_id 作为字符串时,它会在内部将其转换为ObjectId.from_string(_id) 或诸如此类。写入结果时,只需将 OID 转换为字符串即可。

        【讨论】:

          【解决方案5】:

          使用 ObjectIds 作为主键的数据类型对于various reasons 来说很有意义。生成具有低碰撞概率的良好、非顺序、单调的 ID 并非易事,重新发明轮子或从本质上重写功能并不值得麻烦。

          数据映射应该在控制器中完成,并且它们应该使用 DTO 与外部交互。换句话说,当您的数据库使用您的数据库模型时,您的 REST 端点(控制器/模块)应该知道 DTO。

          DTO 看起来与您的模型非常相似,但它们的字段可能会少一些(如果有您不想通过 API 公开的内部数据,则很整洁),并且它们在模型使用 ObjectIds 的地方使用字符串。

          为避免愚蠢地复制代码,请使用 AutoMapper 之类的内容。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-09-19
            • 1970-01-01
            • 2013-06-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多