Keystone.js/mongoose虚域精益记录
Keystone.js / mongoose virtual fields lean record
我正在尝试为包含虚拟字段的 REST API 生成精简记录。
关于如何为Mongoose实现虚拟字段的官方文档:
http://mongoosejs.com/docs/guide.html
我的模型:
var keystone = require('keystone')
, Types = keystone.Field.Types
, list = new keystone.List('Vendors');
list.add({
name : {
first: {type : Types.Text}
, last: {type : Types.Text}
}
});
list.schema.virtual('name.full').get(function() {
return this.name.first + ' ' + this.name.last;
});
list.register();
现在,让我们查询模型:
var keystone = require('keystone'),
vendors = keystone.list('Vendors');
vendors.model.find()
.exec(function(err, doc){
console.log(doc)
});
虚拟字段 name.full 不在此处:
[ { _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White' } }]
但是如果我们这样做:
vendors.model.find()
.exec(function(err, doc){
console.log(doc.name.full); // "Walter White"
});
然后虚拟显示。
我想原因是当我执行 console.log(doc) 时,调用了 Mongoose document.toString() 方法,默认情况下不包括虚拟。很公平。可以理解。
要在您必须采用的任何转换方法中包含虚拟对象:
doc.toString({virtuals: true})
doc.toObject({virtuals: true})
doc.toJSON({virtuals: true})
但是,这包括我不希望我的 REST API 输出给我的用户的密钥:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
_: { name: { last: [Object], first: [Object] } },
list:
List {
options:
{ schema: [Object],
noedit: false,
nocreate: false,
nodelete: false,
autocreate: false,
sortable: false,
hidden: false,
track: false,
inherits: false,
searchFields: '__name__',
defaultSort: '__default__',
defaultColumns: '__name__',
label: 'Vendors' },
key: 'Vendors',
path: 'vendors',
schema:
Schema {
paths: [Object],
subpaths: {},
virtuals: [Object],
nested: [Object],
inherits: {},
callQueue: [],
_indexes: [],
methods: [Object],
statics: {},
tree: [Object],
_requiredpaths: [],
discriminatorMapping: undefined,
_indexedpaths: undefined,
options: [Object] },
schemaFields: [ [Object] ],
uiElements: [ [Object], [Object] ],
underscoreMethods: { name: [Object] },
fields: { 'name.first': [Object], 'name.last': [Object] },
fieldTypes: { text: true },
relationships: {},
mappings:
{ name: null,
createdBy: null,
createdOn: null,
modifiedBy: null,
modifiedOn: null },
model:
{ [Function: model]
base: [Object],
modelName: 'Vendors',
model: [Function: model],
db: [Object],
discriminators: undefined,
schema: [Object],
options: undefined,
collection: [Object] } },
id: '563acf280f2b2dfd4f59bcf3' }
我当然可以随时删除不需要的密钥,但这似乎不太正确:
vendors.model.findOne()
.exec(function(err, doc){
var c = doc.toObject({virtuals: true});
delete c.list;
delete c._;
console.log(c)
});
这产生了我需要的东西:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
id: '563acf280f2b2dfd4f59bcf3' }
没有更好的方法来获得精益记录吗?
一个解决方案是使用像 Lodash (or Underscore) which allows you pick 这样的模块 属性 名称的白名单:
vendors.model.findOne()
.exec(function(err, doc){
var c = _.pick(doc, ['id', 'name.first', 'name.last', 'name.full']);
console.log(c)
});
鉴于您通过 REST API 提供此数据的用例,我认为明确定义 属性 名称的白名单更安全。您甚至可以在您的架构上定义一个虚拟 属性,其中 returns 预定义的白名单:
list.schema.virtual('whitelist').get(function() {
return ['id', 'name.first', 'name.last', 'name.full'];
});
并在多个地方使用它,或者拥有不同版本的白名单,所有这些都在模型层进行管理。
我想你想要 select
方法..像这样:
vendors.model.findOne()
.select('_id __v name').
.exec(function(err, doc){
console.log(c)
});
此外,我个人更喜欢在模式而不是文档上设置 virtuals: true
,但我猜这取决于用例。
我正在尝试为包含虚拟字段的 REST API 生成精简记录。
关于如何为Mongoose实现虚拟字段的官方文档:
http://mongoosejs.com/docs/guide.html
我的模型:
var keystone = require('keystone')
, Types = keystone.Field.Types
, list = new keystone.List('Vendors');
list.add({
name : {
first: {type : Types.Text}
, last: {type : Types.Text}
}
});
list.schema.virtual('name.full').get(function() {
return this.name.first + ' ' + this.name.last;
});
list.register();
现在,让我们查询模型:
var keystone = require('keystone'),
vendors = keystone.list('Vendors');
vendors.model.find()
.exec(function(err, doc){
console.log(doc)
});
虚拟字段 name.full 不在此处:
[ { _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White' } }]
但是如果我们这样做:
vendors.model.find()
.exec(function(err, doc){
console.log(doc.name.full); // "Walter White"
});
然后虚拟显示。
我想原因是当我执行 console.log(doc) 时,调用了 Mongoose document.toString() 方法,默认情况下不包括虚拟。很公平。可以理解。
要在您必须采用的任何转换方法中包含虚拟对象:
doc.toString({virtuals: true})
doc.toObject({virtuals: true})
doc.toJSON({virtuals: true})
但是,这包括我不希望我的 REST API 输出给我的用户的密钥:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
_: { name: { last: [Object], first: [Object] } },
list:
List {
options:
{ schema: [Object],
noedit: false,
nocreate: false,
nodelete: false,
autocreate: false,
sortable: false,
hidden: false,
track: false,
inherits: false,
searchFields: '__name__',
defaultSort: '__default__',
defaultColumns: '__name__',
label: 'Vendors' },
key: 'Vendors',
path: 'vendors',
schema:
Schema {
paths: [Object],
subpaths: {},
virtuals: [Object],
nested: [Object],
inherits: {},
callQueue: [],
_indexes: [],
methods: [Object],
statics: {},
tree: [Object],
_requiredpaths: [],
discriminatorMapping: undefined,
_indexedpaths: undefined,
options: [Object] },
schemaFields: [ [Object] ],
uiElements: [ [Object], [Object] ],
underscoreMethods: { name: [Object] },
fields: { 'name.first': [Object], 'name.last': [Object] },
fieldTypes: { text: true },
relationships: {},
mappings:
{ name: null,
createdBy: null,
createdOn: null,
modifiedBy: null,
modifiedOn: null },
model:
{ [Function: model]
base: [Object],
modelName: 'Vendors',
model: [Function: model],
db: [Object],
discriminators: undefined,
schema: [Object],
options: undefined,
collection: [Object] } },
id: '563acf280f2b2dfd4f59bcf3' }
我当然可以随时删除不需要的密钥,但这似乎不太正确:
vendors.model.findOne()
.exec(function(err, doc){
var c = doc.toObject({virtuals: true});
delete c.list;
delete c._;
console.log(c)
});
这产生了我需要的东西:
{ _id: 563acf280f2b2dfd4f59bcf3,
__v: 0,
name: { first: 'Walter', last: 'White', full: 'Walter White' },
id: '563acf280f2b2dfd4f59bcf3' }
没有更好的方法来获得精益记录吗?
一个解决方案是使用像 Lodash (or Underscore) which allows you pick 这样的模块 属性 名称的白名单:
vendors.model.findOne()
.exec(function(err, doc){
var c = _.pick(doc, ['id', 'name.first', 'name.last', 'name.full']);
console.log(c)
});
鉴于您通过 REST API 提供此数据的用例,我认为明确定义 属性 名称的白名单更安全。您甚至可以在您的架构上定义一个虚拟 属性,其中 returns 预定义的白名单:
list.schema.virtual('whitelist').get(function() {
return ['id', 'name.first', 'name.last', 'name.full'];
});
并在多个地方使用它,或者拥有不同版本的白名单,所有这些都在模型层进行管理。
我想你想要 select
方法..像这样:
vendors.model.findOne()
.select('_id __v name').
.exec(function(err, doc){
console.log(c)
});
此外,我个人更喜欢在模式而不是文档上设置 virtuals: true
,但我猜这取决于用例。