Nodejs + mongodb: как запросить поля $ref?

Я использую 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){
        ...
    });
});

На самом деле я делаю 2 запроса, и сделать 2 объекта. Это своего рода "ленивая загрузка" (не совсем, но почти)

мой вопрос прост : можно ли получить весь граф объектов в одном запросе ?

спасибо

5 ответов


ответ Владимира по-прежнему не действителен в качестве БД.способ разыменования был удален из MongoDB API на Nodejs:

https://www.mongodb.com/blog/post/introducing-nodejs-mongodb-20-driver

объект экземпляра БД был упрощен. Мы удалили следующие методы:

db.разыменование из-за устаревших ссылок на БД на сервере


Нет, ты не можешь.

чтобы разрешить DBRefs, приложение должно выполнить дополнительные запросы для возврата указанных документов. Многие драйверы имеют вспомогательные методы, которые формируют запрос DBRef автоматически. Драйверы не разрешают DBRefs автоматически в документы.

из документов MongoDB http://docs.mongodb.org/manual/reference/database-references/.


можно ли получить родительский объект вместе с его $ref, используя один запрос MongoDB?

нет, это невозможно. У Mongo нет внутренней поддержки refs, поэтому до вашего приложения для их заполнения (см. ответ Бретта).

но можно ли получить родительский объект со всеми его ссылками с одним узлом.команда js?

Да, это возможно. вы можете сделать это с помощью Мангуста. Оно имеет встроенная поддержка населения ref. Вам нужно будет немного изменить свою модель данных, чтобы она работала, но это в значительной степени то, что вы ищете. Конечно, для этого Мангуст сделает те же два запроса MongoDB, что и вы.


нет, очень мало драйверов для MongoDb включают специальную поддержку для DBRef. Есть две причины:--12-->

  1. MongoDb не имеет каких-либо специальных команд для извлечения ссылочных документов. Таким образом, драйверы, которые добавляют поддержку, искусственно заполняют результирующие объекты.
  2. чем больше," голый металл " API, тем меньше это имеет смысл. На самом деле, как. Коллекции MongoDb не содержат схемы, если драйвер NodeJs вернул основной документ при реализации всех ссылок, если код затем сохранит документ без нарушения ссылок, это приведет к встроенному вложенному документу. Конечно, это было бы ужасно.

если ваши значения поля не меняются, я бы не стал беспокоиться о DBRef введите и вместо этого просто сохраните ObjectId напрямую. Как видите, a DBRef действительно не дает никаких преимуществ, кроме как требует много дубликатов дискового пространства для каждой ссылки, так как более богатый объект должен храниться вместе с его типом информация. В любом случае следует учитывать потенциально ненужные накладные расходы на хранение строки, содержащей документы указанной коллекции.

многие разработчики и MongoDb, Inc. добавили слой сопоставления документа объекта поверх существующих базовых драйверов. Один из популярных вариантов для MongoDb и Nodejs-Мангуст. Поскольку сервер MongoDb не имеет реальной осведомленности о ссылочных документах, ответственность за ссылки переходит к клиенту. Как это чаще последовательно ссылаться на определенную коллекцию из данного документа, Мангуст позволяет определить ссылку как схему. Мангуст не лишен схемы.

если вы принимаете наличие и использование схемы полезно, то Мангуст определенно стоит посмотреть. Он может эффективно извлекать пакет связанных документов (из одной коллекции) из набора документов. Он всегда использует собственный драйвер, но обычно делает операции чрезвычайно эффективно и занимает некоторые из нудная работа из более сложных архитектур приложений.

я настоятельно рекомендую вам взглянуть на 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
})

если вместо findById, который всегда возвращает один документ,find С populate, все возвращенные документы' details свойство будет заполнено автоматически. Это тоже умно, что он будет запрашивать одни и те же ссылочные документы несколько раз.

если вы не используете Мангуста, я бы предложил вам рассмотреть слой кэширования, чтобы избежать выполнения ссылок на стороне клиента, когда это возможно, и использовать $in оператор запроса для пакетной обработки как можно больше.


Я достигаю желаемого результата со следующим примером:

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

Не уверен, что это решение лучше всего, но это самое простое решение, которое я нашел.