Javascript Nodejs+;mongodb:如何查询$ref字段?

Javascript Nodejs+;mongodb:如何查询$ref字段?,javascript,node.js,mongodb,dbref,Javascript,Node.js,Mongodb,Dbref,我正在使用MongoDB和nodejs REST服务,该服务公开了存储在其中的数据。我有一个关于如何查询我使用$ref的数据的问题 以下是一个对象的示例,其中包含对另一个集合中另一个对象(细节)的引用: { "_id" : ObjectId("5962c7b53b6a02100a000085"), "Title" : "test", "detail" : { "$ref" : "ObjDetail", "$id" : ObjectId("5

我正在使用MongoDB和nodejs REST服务,该服务公开了存储在其中的数据。我有一个关于如何查询我使用$ref的数据的问题

以下是一个对象的示例,其中包含对另一个集合中另一个对象(细节)的引用:

{
    "_id" : ObjectId("5962c7b53b6a02100a000085"),
    "Title" : "test",
    "detail" : {
        "$ref" : "ObjDetail",
        "$id" : ObjectId("5270c7b11f6a02100a000001")
    },
    "foo" : bar
}
实际上,使用Node.js和mongodb模块,我做了以下工作:

db.collection("Obj").findOne({"_id" : new ObjectID("5962c7b53b6a02100a000085"},
function(err, item) {
    db.collection(item.$ref).findOne({"_id" : item.$id}, function(err,subItem){
        ...
    });
});
事实上,我进行了两次查询,得到了两个对象。这是一种“延迟加载”(不完全是,但几乎是)

我的问题很简单:是否可以在一个查询中检索整个对象图

谢谢

不,不行

要解析DBREF,应用程序必须执行其他查询以返回引用的文档。许多驱动程序都有自动形成DBRef查询的助手方法。驱动程序不会自动将DBREF解析为文档


从MongoDB文档中。

是否可以使用单个MongoDB查询获取父对象及其$ref

不,这是不可能的。 Mongo没有对REF的内部支持,因此填充它们取决于应用程序(请参阅)

但是,是否可以使用单个node.js命令获取父对象及其所有ref


是的,这是可能的。你可以用。它有ref的人口支持。您需要稍微更改数据模型以使其正常工作,但这正是您所需要的。当然,要做到这一点,Mongoose将执行与您相同的两个MongoDB查询。

不,MongoDB的驱动程序很少包含对
DBRef
的特殊支持。原因有两个:

  • MongoDb没有任何特殊的命令来检索引用的文档。因此,添加支持的驱动程序是人工填充结果对象
  • API的“裸机”越多,其意义就越小。事实上,正如。MongoDb集合是无模式的,如果NodeJs驱动程序带回实现了所有引用的主文档,如果代码随后保存文档而不破坏引用,则会生成嵌入的子文档。当然,那会是一团糟
  • 除非字段值不同,否则我不会使用
    DBRef
    类型,而是直接存储
    ObjectId
    。正如您所看到的,
    DBRef
    除了为每个引用需要大量重复的磁盘空间外,实际上没有任何好处,因为更丰富的对象必须与其类型信息一起存储。无论哪种方式,您都应该考虑存储包含引用集合文档的字符串的潜在不必要开销。p> 许多开发人员和MongoDb,Inc.在现有基本驱动程序的基础上添加了对象文档映射层。MongoDb和Nodejs的一个流行选项是Mongoose。由于MongoDb服务器对引用的文档没有真正的感知,因此引用的责任转移到了客户端。由于一致引用给定文档中的特定集合更为常见,因此Mongoose可以将引用定义为模式。Mongoose不是无模式的

    如果您接受拥有并使用模式是有用的,那么Mongoose绝对值得一看。它可以从一组文档中高效地获取一批相关文档(来自单个集合)。它总是使用本机驱动程序,但它通常非常高效地执行操作,并从更复杂的应用程序体系结构中消除一些繁琐的工作

    我强烈建议您看看
    populate
    方法(),看看它能做什么

    Demo     /* Demo would be a Mongoose Model that you've defined */
    .findById(theObjectId)
    .populate('detail')
    .exec(function (err, doc) {
      if (err) return handleError(err);
      // do something with the single doc that was returned
    })
    
    如果使用
    populate
    ,而不是始终返回单个文档的
    findById
    ,则所有返回文档的
    详细信息
    属性将自动填充。它还可以多次请求相同的引用文档


    如果您不使用MangeOSE,我建议您考虑一个缓存层以避免在可能的时候做客户端引用连接,并使用<代码> $$在/<代码>查询运算符中尽可能批量。p> 我通过下一个示例达到了所需的结果:

    collection.find({}, function (err, cursor) {
        cursor.toArray(function (err, docs) {
            var count = docs.length - 1;
            for (i in docs) {
                (function (docs, i) {
                    db.dereference(docs[i].ref, function(err, doc) {
                        docs[i].ref = doc;
                        if (i == count) {
                            (function (docs) {
                                console.log(docs);
                            })(docs);
                        }
                    });
                })(docs, i)
            }
        });
    });
    

    不确定it解决方案是最好的,但这是我发现的最简单的解决方案。

    Vladimir的答案仍然无效,因为db.dereference方法已从MongoDB Nodejs API中删除:

    db实例对象已简化。我们已删除以下方法:

    由于服务器中不推荐使用db引用,导致db.dereference


    据我所知,节点mongodb本机驱动程序无法为您解析这些引用。谢谢,我来看看mongoose。