我正在使用Monger库从Clojure访问Mongo数据库。有一件事让我很恼火,那就是在ObjectId实例和字符串之间来回切换。
例如,这段代码(mc/find-maps "posts" {})
将计算为映射,_id
条目的值设置为ObjectId
类的实例,而在我的应用程序中,我发现简单地将其作为一个字符串更有用,因为我知道它是唯一的。
另一方面,对于像(mc/find-map-by-id "posts" (new ObjectId id))
这样的表达式,其中我确实为id
参数使用了一个String对象,我必须使用它来构造ObjectId
的实例。
有没有一种方法可以使_id
的值在应用程序中的Strings和mongo端的ObjectId之间自动透明地转换?某种选项在启用时会创建带有id字符串表示的映射,反之亦然,在查询中用作参数时会转换id字符串表示t对象id?
如果没有,还有哪些其他策略可用?
我和你分享这一点上的痛苦。返回ObjectID是很烦人的,因为您总是必须来回转换,如果您忘记了,那么很难发现错误。
您最好的选择可能是包装驱动程序代码以自动进行转换。因此,将find、findOne、insert替换为一个查看类型并自动进行转换的瘦包装器,无论您是进入还是退出。
不幸的是,我认为没有更简单的方法了。
我参加聚会有点晚了,但为了子孙后代,我不得不提一提。
我不想解决自动str->ObjectID部分,因为让代码了解哪些字符串必须被视为ObjectID,哪些不能被视为。但对于ObjectID->str的一半,有一个解决方案。
我最终扩展了monger.conversion/ConvertFromDBObject
协议,如下所示:
(extend-protocol ConvertFromDBObject
ObjectId
(from-db-object [input keywordize]
(str input)))
from-db-object
在所有读作映射操作中被调用,因此这解决了读取部分。至于将ObjectID转换为插入和更新结果的字符串,我还没有找到任何优雅的解决方案,也没有为映射扩展相同的协议,并在包装器函数中对插入和更新操作的结果调用from-db-object
。为地图扩展协议看起来是这样的(完全是从DBObject
:的原始实现中窃取的
(extend-protocol ConvertFromDBObject
; copied over from the implementation for DBObject
clojure.lang.IPersistentMap
(from-db-object [input keywordize]
(reduce (if keywordize
(fn [m ^String k]
(assoc m (keyword k) (from-db-object (.get input k) true)))
(fn [m ^String k]
(assoc m k (from-db-object (.get input k) false))))
{} (.keySet input))))