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

3npbholx  于 2023-05-27  发布在  Java
关注(0)|答案(6)|浏览(256)

我正在使用MongoDB和一个nodejs REST服务,它公开了我存储在里面的数据。我有一个关于如何使用$ref查询我的数据的问题。
下面是一个Object的示例,它包含对另一个集合中的另一个对象(detail)的引用:

{
    "_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){
        ...
    });
});

实际上,我做了两个查询,得到了两个对象。这是一种“延迟加载”(不完全是,但几乎是)
我的问题很简单是否可以在一个查询中检索整个对象图?
谢谢你

a64a0gku

a64a0gku1#

不你不能
若要解析DBRefs,应用程序必须执行其他查询以返回引用的文档。许多驱动程序都有自动形成DBRef查询的helper方法。驱动程序不会自动将DBRef解析为文档。
MongoDB文档http://docs.mongodb.org/manual/reference/database-references/

ojsjcaue

ojsjcaue2#

是否可以使用单个MongoDB查询来获取父对象沿着$ref?

**不,这是不可能的。**Mongo内部不支持引用,所以要由你的应用程序来填充它们(参见Brett的回答)。

但是是否可以用一个node.js命令来获取父对象及其所有ref?

**是的,这是可能的。**你可以用Mongoose来做。它有内置裁判的人口支持。您需要稍微更改数据模型以使其正常工作,但这正是您所需要的。当然,为了做到这一点,Mongoose会像你一样做两个MongoDB查询。

omvjsjqw

omvjsjqw3#

弗拉基米尔的答案不再有效,因为db.dereference方法已从MongoDB Nodejs API中删除:
https://www.mongodb.com/blog/post/introducing-nodejs-mongodb-20-driver
db示例对象已被简化。我们删除了以下方法:
由于服务器中的db引用被弃用

jhdbpxl9

jhdbpxl94#

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

  1. MongoDb没有任何特殊的命令来检索引用的文档。因此,添加支持的驱动程序会人为地填充结果对象。
  2. API越是“裸机”,就越没有意义。事实上,作为。MongoDb集合是无模式的,如果NodeJs驱动程序带回了实现了所有引用的主文档,如果代码然后保存了文档而没有破坏引用,它将导致嵌入的子文档。当然,那会是一团糟。
    除非您的字段值不同,否则我不会为DBRef类型而烦恼,而是直接存储ObjectId。正如您所看到的,DBRef实际上没有提供任何好处,除了需要为每个引用提供大量重复的磁盘空间,因为更丰富的对象必须与其类型信息沿着存储。无论哪种方式,都应该考虑存储包含被引用集合文档的字符串可能带来的不必要开销。
    许多开发人员和MongoDb,Inc.在现有的基础驱动程序之上添加了一个对象文档Map层。MongoDb和Nodejs的一个流行选择是Mongoose。由于MongoDb服务器对引用的文档没有真实的的意识,因此引用的责任转移到客户端。由于一致地引用给定文档中的特定集合更为常见,Mongoose使将引用定义为Schema成为可能。Mongoose不是无模式的。
    如果您接受拥有和使用Schema是有用的,那么Mongoose绝对值得一看。它可以有效地从一组文档中获取一批相关文档(从单个集合中)。它总是使用本机驱动程序,但它通常非常有效地执行操作,并从更复杂的应用程序架构中消除一些繁琐的工作。
    我强烈建议你看看populate方法(here),看看它能做什么。
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
})

如果使用find而不是findById(它总是返回单个文档),则populate将自动填充所有返回文档的details属性。它会多次请求相同的引用文档,这也是很聪明的。
如果你不使用Mongoose,我建议你考虑一个缓存层,以避免尽可能地进行客户端引用连接,并使用$in查询操作符来尽可能多地进行批处理。

5anewei6

5anewei65#

我用下一个例子达到了预期的结果:

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

我不确定它的解决方案是最好的,但它是我找到的最简单的解决方案。

gr8qqesn

gr8qqesn6#

事实上,你可以。方法是使用$lookup阶段和运算符聚合,下面是MongoDB文档中的一些示例。

相关问题