Мангуст: что случилось с "_doc"?

Кажется, что Mongoose делает что-то действительно классное внутри.

1 var Foo = new mongoose.model('Foo', new mongoose.Schema({a: String, b: Number}));
2 var foo = new Foo({a: 'test; b: 42}); 
3 var obj = {c: 1};
4 foo.goo = obj;                  // simple object assignment. obj should be 
                                  //   passed by reference to foo.goo. recall goo
                                  //   is not defined in the Foo model schema

5 console.log(foo.goo === obj);   // comparison directly after the assignment
    // => false, does not behave like normal JS object

По сути, каждый раз, когда вы пытаетесь разобраться со свойствами модели Mongoose, которые не являются

а) определено в схеме модели или

б) определяется как тот же тип (массив, объект,..)... модель даже не ведет себя как обычный объект Javascript.

Переключение линии 4 на foo._doc.goo = obj приводит к выводу на консоль true.

редактировать: пытаться воспроизвести странности

Пример 1:

 // Customer has a property 'name', but no property 'text'
 // I do this because I need to transform my data slightly before sending it
 // to client.
 models.Customer.find({}, function(err, data) {
     for (var i=0, len=data.length; i<len; ++i) {
        data[i] = data[i]._doc;            // if I don't do this, returned data
                                           // has no 'text' property
        data[i].text = data[i].name;       
    }
    res.json({success: err, response:data});
});

Ответ 1

Обновление

Возможно, я неправильно понял ваш первоначальный вопрос, но теперь похоже, что характер вашего вопроса изменился, поэтому приведенная ниже информация не актуальна, но я оставляю ее. :)

Я проверил ваш код, и он отлично работает для меня. Mongoose не выполняет никакого специального кода, когда вы устанавливаете свойства, которые не являются частью схемы (или несколько других специальных свойств). JavaScript в настоящее время не поддерживает вызов кода для свойств, которые еще не существуют (поэтому Mongoose не может помешать, например, набору свойства goo).

Итак, когда вы устанавливаете свойство:

foo.goo = { c: 1 };

Мангуст не участвует. Если ваш console.log был чем-то отличным от кода, который вы отображали, я мог видеть, что он может сообщать неправильно.

Кроме того, когда вы send возвращаете результаты в виде JSON, вызывается JSON.stringify, который вызывает toString для вашей модели Mongoose. Когда это происходит, Mongoose использует только свойства, определенные в схеме. Таким образом, никакие дополнительные свойства не отправляются обратно по умолчанию. Вы изменили природу массива data, чтобы напрямую указывать на данные Mongoose, поэтому он позволяет избежать этой проблемы.

Подробности о нормальном поведении

Когда вы устанавливаете свойство goo с помощью Mongoose, происходит довольно много вещей. Mongoose создает средства получения/установки свойств с помощью Object.defineProperty (некоторые документы). Итак, когда вы устанавливаете свойство goo, которое вы определили как [String], происходит несколько вещей:

  1. Код Mongoose вызывается до установки значения в экземпляр объекта (в отличие от простого объекта JavaScript)
  2. Mongoose создает массив (опционально) для хранения данных (MongooseArray), который будет содержать данные массива. В приведенном вами примере, поскольку вы не передали массив, он будет создан.
  3. Mongoose попытается привести ваши данные к нужному типу
  4. Он вызовет toString для данных, переданных как часть приведения.

Таким образом, в результате документ теперь содержит массив с toString версией переданного вами объекта.

Если вы проверили содержимое свойства goo, вы увидите, что теперь это массив с одним элементом, который является строкой, содержащей [object Object]. Если бы вы выбрали более базовый тип или соответствовали типу хранения целевого свойства, вы бы увидели, что базовая проверка на равенство сработала бы.

Ответ 2

Я застрял на этом сегодня... Сводил меня с ума. Не уверен, что нижеследующее является хорошим решением (и OP тоже об этом упомянул), но я решил эту проблему.

Мой автомобильный объект:

 cars = [{"make" : "Toyota"}, {"make" : "Kia"}];

Действие:

console.log("1. Cars before the color: " + car);

cars.forEach(function(car){
     car.colour = "Black";   //color is NOT defined in the model. 
});

console.log("2. Cars after the color: " + car);

Проблемный вывод на консоль:

   1. Cars before the color: [{"make" : "Toyota"}, {"make" : "Kia"}];
   2. Cars after the color: [{"make" : "Toyota"}, {"make" : "Kia"}];   //No change! No new colour properties :(

Если вы попытаетесь передать это свойство, которое не было определено в модели, через документ (например, car. _Doc.color = "black"), оно будет работать (это свойство цвета будет назначено для каждого автомобиля), но вы не сможете кажется, что доступ к нему через EJS (интерфейс) по какой-то причине.

Решение: (Опять же, не уверен, что это лучший способ... но у меня это сработало): Добавьте новое свойство (цвет) в модель автомобиля.

var carSchema = mongoose.Schema({
   make: String,
   color: String   //New property.
})

После переопределения модели все работало как обычно/ожидалось (не нужно никаких "хаков" и т.д.), И я прожил еще один день; надеюсь, это поможет кому-то еще.

Ответ 3

С моделями Mongoose есть некоторые странности, и вы должны убедиться, что у Mongoose еще нет созданной модели в массиве моделей.

Вот мое решение:

import mongoose from 'mongoose';
createModel = (modelName="foo", schemaDef, schemaOptions = {})=> {
  const { Schema } = mongoose;
  const schema = Schema(schemaDef, schemaOptions);
  const Model = mongoose.models[modelName] || mongoose.model(modelName, schema);
  return Model;
}

Я использую свой собственный класс моделей мангуста и базовый класс для своих моделей. Я сделал это, и это должно работать для вас.