我使用Monger库从Clojure访问Mongo数据库。令我烦恼的一件事是在ObjectId实例和字符串之间来回切换。
例如,此代码(mc/find-maps "posts" {})
将评估映射,其中_id
条目的值设置为ObjectId
类的实例,而在我的应用中,我发现它更简单把它作为一个字符串,我知道它是独一无二的。
另一方面,对于(mc/find-map-by-id "posts" (new ObjectId id))
之类的表达式,我在id
参数中使用String对象,我必须使用它来构造ObjectId
的实例。
有没有办法让_id
的值自动透明地在应用程序中的字符串和mongo端的ObjectId之间进行转换?某种选项在启用时会创建带有ids字符串表示的地图,反之亦然会在用作查询中的参数时转换ids t对象ID的字符串表示形式?
如果没有,还有哪些其他策略?
答案 0 :(得分:1)
我在这一点上与你分享痛苦。回到ObjectID是很烦人的,因为你总是要来回转换,如果你忘了,那就很难捕捉到它。
您最好的选择可能是包装驱动程序代码以自动执行转换。因此,使用查看类型的瘦包装替换find,findOne,insert,无论您是进入还是退出,都会自动进行转换。
不幸的是,我认为没有更简单的方法。
答案 1 :(得分:0)
我参加聚会有点晚了,但必须为子孙后代提及。
由于要让代码了解必须将哪些字符串视为ObjectID以及哪些不能视为ObjectID的代码很复杂,因此我不打算解决自动的str-> 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))))