Мангуст: что случилось с "_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]
, происходит несколько вещей:
- Код Mongoose вызывается до установки значения в экземпляр объекта (в отличие от простого объекта JavaScript)
- Mongoose создает массив (опционально) для хранения данных (
MongooseArray
), который будет содержать данные массива. В приведенном вами примере, поскольку вы не передали массив, он будет создан.
- Mongoose попытается привести ваши данные к нужному типу
- Он вызовет
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;
}
Я использую свой собственный класс моделей мангуста и базовый класс для своих моделей. Я сделал это, и это должно работать для вас.