为了获得更好的存储空间并使用UUID作为主键,我自定义了_id的默认功能,以UUID的形式存储为二进制bson类型4.然后我设置了一个虚拟的id来返回_id的值。 / p>
以下是使用ES6的示例模式:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
require('mongoose-uuid2')(mongoose);
const UUID = mongoose.Types.UUID;
const uuid = require('node-uuid');
const bson = require('bson');
const schema_options = {
id: false,
getters: true,
virtuals: true,
toObject: {
versionKey: false,
transform: function (doc, ret) {
delete ret.__v;
//delete ret._id;
}
},
toJSON: {
versionKey: false,
transform: function (doc, ret) {
//delete ret._id;
delete ret.__v
}
}
};
const BaseSchema = new Schema (
{
_id: { type: UUID, default: uuid.v4, required: true },
code: { type: String },
name: { type: String },
timestamps: {
created: {type: Date, required: true},
updated: {type: Date, required: true}
},
__v: { type: Number, select: false}
}, schema_options
);
class BaseSchemaClass {
//virtuals
get id() {
return this._id;
}
set id(uuid_string){
console.log(uuid_string);
let uuid_parse = uuid.parse(uuid_string);
console.log(uuid_parse);
let id_buffer = new mongoose.Types.Buffer(uuid_parse);
id_buffer.subtype(bson.Binary.SUBTYPE_UUID);
console.log(id_buffer);
this._id = id_buffer.toObject();
}
//private
static convert_uuid_string_to_buffer (uuid_string) {
var uuid_parse = uuid.parse(uuid_string);
var id = new db.Types.Buffer(uuid_parse);
id.subtype(bson.Binary.SUBTYPE_UUID);
return id.toObject();
}
}
BaseSchema.loadClass(BaseSchemaClass);
module.exports = BaseSchema;
架构数据似乎更新,您可以按预期读取数据。此外,似乎保存到数据库也按预期发生。
以下是一个示例记录:
{ "_id" : BinData(4,"yyfw80jURj+35wguKCKJRg=="), "timestamps" : { "updated" : ISODate("2018-01-28T19:47:05.825Z"), "created" : ISODate("2018-01-28T19:47:05.825Z") }, "code" : "MAR", "name" : "Michael", "__v" : 0 }
但是,当使用mongoose查找记录时,使用非“_id”字段时,“_ id”字段不会返回。虚拟后退_id并且未定义。
以下是使用架构的示例。
const BaseSchema = require('./schemas/base');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
mongoose.set('debug', true);
mongoose.Promise = require("bluebird");
let db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
const BaseModel = mongoose.model('Base', BaseSchema);
let base_document = new BaseModel({code: "MAR", name: "Michael", timestamps :{updated: new Date(), created: new Date() }});
console.log(base_document.id)
console.log(base_document.code)
base_document.save()
.then(() => {
return Promise.resolve();
})
.then(() => {
return BaseModel.findOne({code: "MAR"}).exec();
})
.then((record) => {
//fails
console.log(record.id)
console.log(record.code)
console.log(record);
return BaseModel.findByIdAndUpdate(record.id, { $set: { name: 'Steve', code: "STV" }});
})
.then(() => {
return BaseModel.findOne({name: "Steve"}).exec();
})
.then((record) => {
//fails
console.log(record.id);
console.log(record.code);
console.log(record);
db.close();
})
.catch((err) => {
console.log(err);
db.close();
});
});
我不知道为什么_id没有在架构中返回,我尝试了查找的变体并找到了上面的更新,但它仍然没有返回_id。我在确定问题时需要一些帮助。
以下是我正在使用的npm包的版本
"bluebird": "^3.5.1",
"bson": "^1.0.4",
"mongoose": "^5.0.1",
"mongoose-uuid2": "^2.0.2",
"node-uuid": "^1.4.8"
我尝试使用节点9.2.0和8.9.4,结果相同。
我也在使用mongo 3.2
答案 0 :(得分:1)
问题是mongoose-uuid2
取决于mongoose 4.x
,但您的包依赖项中有^5.0.1
。
此配置使您的包管理器安装两个不同版本的mongoose及其依赖项:代码为5.x,mongoose-uuid2
为4.x.
因此,当将_id
字段的二进制值转换为UUID
模式类型时,mongoose-uuid2/index.js:101
处的此条件的计算结果为false:
if (value instanceof mongoose.Types.Buffer.Binary)
return value;
这是因为4.x和5.x版本中的mongoose.Types.Buffer.Binary
与节点的观点不同。即使他们使用完全相同版本的mongodb
和bson
包。
最后,它会引发"Could not cast _id to uuid."
错误,并且mongoose在文档中不包含_id
字段。
答案 1 :(得分:0)
在@serge的一些指导和帮助下,我找到了另一种解决方案。基本上,mongoose-uuid2(https://github.com/niahmiah/mongoose-uuid)软件包仅支持更新mongoose 4,因为版本5支持新的ES6构造,此外,由于版本1.0中bson合同中引入的更改,它仅支持bson 0.4。为了向后兼容,我理解为什么会这样。
我最终不得不创建一个mongoose-uuid2的分叉,https://github.com/thxmike/mongoose-uuid使用新的bson合约和新的mongoose api。
我已经发出拉取请求,但为了向后兼容,这可能会失败。 我不确定作者是否以及如何解决这个问题。 https://github.com/niahmiah/mongoose-uuid/pull/11
编辑: @serge:在主回购中解决了这个问题,现在可以使用Mongoose 5。 https://github.com/niahmiah/mongoose-uuid。真棒