Mongoose返回的一大串是什么鬼?

mongoose

  • 我们在model文件配置projectInfo的schema,我们都知道,每一个schema实例都映射一个mongodb的表,可以说schema是mongoose操纵mongodb的灵魂所在。
var mongoose = require('mongoose')
mongoose.Promise = require('bluebird')
var schema = mongoose.Schema
var ProjectSchema = new schema({
  id: schema.ObjectId,
  projectName: {type: String, unique: true},
)
mongoose.model('ProjectInfo', ProjectSchema)

如果这个时候有一个需求,要求读取rojectInfo表中的一个accountPermissions字段,该字段是一个数组。由于不一定所有文档都需要这个字段,所以并没有在model文件中做相关配置。
我们利用find()方法进行查询,代码如下:

await ProjectInfos.find(null, { projectName: 1, accountPermissions: 1 })
      .exec((err, docs) => {
        projectList = docs
        console.log(docs[0].accountPermissions)
      })

按照我们的预期,应该是在控制台得到第一个符合文档的accountPermissions数组。现实却十分骨感,居然得到undefined。这个问题让很多比较熟悉js的开发者痛苦不堪,甚至怀疑人生。得到的doc不是一个对象吗?对象中的属性应该可以用obj.property获得才对。
可是我们却得到了undefined,太诡异了吧!
带着这个问题,我们把查询结果第0项,即docs[0]打印出来,控制台却出现了如下一大串:

model {
  '$__': InternalCache {
    strictMode: true,
    selected: { projectName: 1, accountPermissions: 1 },
    shardval: undefined,
    saveError: undefined,
    validationError: undefined,
    adhocPaths: undefined,
    removing: undefined,
    inserting: undefined,
    version: undefined,
    getters: {},
    _id: 5c13064a3ce9e71c5bdedf29,
    populate: undefined,
    populated: undefined,
    wasPopulated: false,
    scope: undefined,
    activePaths: StateMachine {
      paths: [Object],
      states: [Object],
      stateNames: [Array]
    },
    pathsToScopes: {},
    ownerDocument: undefined,
    fullPath: undefined,
    emitter: EventEmitter {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: 0
    },
    '$options': true
  },
  isNew: false,
  errors: undefined,
  _doc: {
    accountPermissions: [
      '5e09a25cd77ad90b2f63cee7',
      '5c0f150f9325280349519b20',
      '5df2f8b330750c2b8f2b8725'
    ],
    projectName: 'aaa',
    _id: 5c13064a3ce9e71c5bdedf29
  },
  '$init': true
}

没能如愿得到类似如下的结果:

doc = {
  _id: 5c13064a3ce9e71c5bdedf29,
  projectName: 'aaa',
  accountPermissions: [
    '5e09a25cd77ad90b2f63cee7',
    '5c0f150f9325280349519b20',
    '5df2f8b330750c2b8f2b8725'
  ]
}

看来事情不那么简单,利用js的原型知识,我们对比一下docs[0]和doc的隐式原型。结果docs[0]的隐式原型并不是{},也就是说得到的docs根本就不是一个正常的js对象。

console.log("***************************************************");      
console.log(docs[0])
console.log("***************************************************");      
console.log(docs[0].__proto__)
console.log("***************************************************");      
console.log(docs[0].__proto__.__proto__)
console.log("***************************************************");      
console.log(docs[0].__proto__.__proto__.__proto__)
console.log("***************************************************");      
console.log(docs[0].__proto__.__proto__.__proto__.__proto__)

如上代码,我们以此打印,结果如下:

***************************************************
model {
  '$__': InternalCache {
    strictMode: true,
    selected: { projectName: 1, accountPermissions: 1 },
    shardval: undefined,
    saveError: undefined,
    validationError: undefined,
    adhocPaths: undefined,
    removing: undefined,
    inserting: undefined,
    version: undefined,
    getters: {},
    _id: 5c13064a3ce9e71c5bdedf29,
    populate: undefined,
    populated: undefined,
    wasPopulated: false,
    scope: undefined,
    activePaths: StateMachine {
      paths: [Object],
      states: [Object],
      stateNames: [Array]
    },
    pathsToScopes: {},
    ownerDocument: undefined,
    fullPath: undefined,
    emitter: EventEmitter {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: 0
    },
    '$options': true
  },
  isNew: false,
  errors: undefined,
  _doc: {
    accountPermissions: [
      '5e09a25cd77ad90b2f63cee7',
      '5c0f150f9325280349519b20',
      '5df2f8b330750c2b8f2b8725'
    ],
    projectName: 'aaa',
    _id: 5c13064a3ce9e71c5bdedf29
  },
  '$init': true
}
***************************************************
model {
  db: NativeConnection {
    base: Mongoose {
      connections: [Array],
      models: [Object],
      modelSchemas: [Object],
      options: [Object],
      plugins: [Array]
    },
    collections: {
      users: [NativeCollection],
      projectinfos: [NativeCollection],
      histories: [NativeCollection],
      ioscerts: [NativeCollection],
      androidcerts: [NativeCollection],
      androidgitinfos: [NativeCollection],
      iosgitinfos: [NativeCollection],
      rolepermissions: [NativeCollection],
      gitlabaccounts: [NativeCollection],
      logosources: [NativeCollection],
      npmrepositories: [NativeCollection],
      notificationtypes: [NativeCollection]
    },
    models: {
      User: [Function],
      ProjectInfo: [Function],
      History: [Function],
      IOSCert: [Function],
      ANDROIDCert: [Function],
      ANDROIDGitInfo: [Function],
      IOSGitInfo: [Function],
      RolePermission: [Function],
      GitLabAccount: [Function],
      LogoSource: [Function],
      NPMRepository: [Function],
      NotificationType: [Function]
    },
    config: { autoIndex: true },
    replica: false,
    hosts: null,
    host: 'localhost',
    port: 27017,
    user: null,
    pass: null,
    name: 'db',
    options: null,
    otherDbs: [],
    states: [Object: null prototype] {
      '0': 'disconnected',
      '1': 'connected',
      '2': 'connecting',
      '3': 'disconnecting',
      '4': 'unauthorized',
      '99': 'uninitialized',
      disconnected: 0,
      connected: 1,
      connecting: 2,
      disconnecting: 3,
      unauthorized: 4,
      uninitialized: 99
    },
    _readyState: 1,
    _closeCalled: false,
    _hasOpened: true,
    _listening: false,
    _connectionOptions: {},
    db: Db {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      s: [Object],
      serverConfig: [Getter],
      bufferMaxEntries: [Getter],
      databaseName: [Getter]
    }
  },
  discriminators: undefined,
  __v: [Getter/Setter],
  _id: [Getter/Setter],
  history: [Getter/Setter],
  RepositoryLink: [Getter/Setter],
  APPVersion: [Getter/Setter],
  bundleId: [Getter/Setter],
  android: [Getter/Setter],
  ios: [Getter/Setter],
  projectName: [Getter/Setter],
  id: [Getter/Setter],
  schema: Schema {
    obj: {
      id: [Function],
      projectName: [Object],
      ios: [Object],
      android: [Object],
      bundleId: [Function: String],
      APPVersion: [Function: String],
      RepositoryLink: [Object],
      history: [Array]
    },
    paths: {
      id: [ObjectId],
      projectName: [SchemaString],
      'ios.git': [ObjectId],
      'ios.env': [SchemaArray],
      'ios.cert': [SchemaArray],
      'ios.workSpaceName': [SchemaString],
      'ios.npmModules': [SchemaString],
      'ios.releaseMethod': [SchemaString],
      'ios.debugShaCode': [SchemaString],
      'ios.releaseShaCode': [SchemaString],
      'ios.schema': [DocumentArray],
      'ios.projectType': [SchemaString],
      'ios.p12File': [SchemaString],
      'ios.p12Password': [SchemaString],
      'ios.p12': [DocumentArray],
      'android.git': [ObjectId],
      'android.env': [SchemaArray],
      'android.cert': [SchemaArray],
      'android.schema': [DocumentArray],
      'android.npmModules': [SchemaString],
      'android.projectType': [SchemaString],
      'android.isJPushProject': [SchemaBoolean],
      bundleId: [SchemaString],
      APPVersion: [SchemaString],
      RepositoryLink: [ObjectId],
      history: [SchemaArray],
      _id: [ObjectId],
      __v: [SchemaNumber]
    },
    aliases: {},
    subpaths: {},
    virtuals: {},
    singleNestedPaths: {},
    nested: { ios: true, android: true },
    inherits: {},
    callQueue: [ [Array], [Array], [Array], [Array], [Array], [Array] ],
    _indexes: [],
    methods: {},
    statics: {},
    tree: {
      id: [Function],
      projectName: [Object],
      ios: [Object],
      android: [Object],
      bundleId: [Function: String],
      APPVersion: [Function: String],
      RepositoryLink: [Object],
      history: [Array],
      _id: [Object],
      __v: [Function: Number]
    },
    query: {},
    childSchemas: [ [Object], [Object], [Object] ],
    plugins: [ [Object], [Object], [Object], [Object] ],
    s: { hooks: [Kareem], kareemHooks: [Object] },
    _userProvidedOptions: { usePushEach: true },
    options: {
      usePushEach: true,
      retainKeyOrder: false,
      typeKey: 'type',
      id: true,
      noVirtualId: false,
      _id: true,
      noId: false,
      validateBeforeSave: true,
      read: null,
      shardKey: null,
      autoIndex: null,
      minimize: true,
      discriminatorKey: '__t',
      versionKey: '__v',
      capped: false,
      bufferCommands: true,
      strict: true,
      pluralization: true
    },
    '$globalPluginsApplied': true,
    _requiredpaths: []
  },
  collection: NativeCollection {
    collection: Collection { s: [Object] },
    opts: {
      bufferCommands: true,
      capped: false,
      '$wasForceClosed': undefined
    },
    name: 'projectinfos',
    collectionName: 'projectinfos',
    conn: NativeConnection {
      base: [Mongoose],
      collections: [Object],
      models: [Object],
      config: [Object],
      replica: false,
      hosts: null,
      host: 'localhost',
      port: 27017,
      user: null,
      pass: null,
      name: 'db',
      options: null,
      otherDbs: [],
      states: [Object: null prototype],
      _readyState: 1,
      _closeCalled: false,
      _hasOpened: true,
      _listening: false,
      _connectionOptions: {},
      db: [Db]
    },
    queue: [],
    buffer: false,
    emitter: EventEmitter {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined
    }
  },
  '$__original_save': [Function] { numAsyncPres: 0 },
  save: [Function: wrappedPointCut] {
    '$originalFunction': '$__original_save',
    '$isWrapped': true
  },
  _pres: {
    '$__original_save': [ [Function], [Function], [Function] ],
    '$__original_remove': [ [Function] ]
  },
  _posts: { '$__original_save': [], '$__original_remove': [] },
  '$__original_remove': [Function] { numAsyncPres: 1 },
  remove: [Function: wrappedPointCut] {
    '$originalFunction': '$__original_remove',
    '$isWrapped': true
  },
  '$__original_validate': [Function],
  validate: [Function: wrappedPointCut] {
    '$originalFunction': '$__original_validate',
    '$isWrapped': true
  }
}
***************************************************
Model {
  '$isMongooseModelPrototype': true,
  '$__handleSave': [Function],
  '$__save': [Function],
  save: [Function],
  '$__delta': [Function],
  '$__version': [Function],
  increment: [Function: increment],
  '$__where': [Function: _where],
  remove: [Function: remove],
  model: [Function: model]
}
***************************************************
Document {
  on: [Function],
  once: [Function],
  emit: [Function],
  listeners: [Function],
  removeListener: [Function],
  setMaxListeners: [Function],
  removeAllListeners: [Function],
  addListener: [Function],
  '$__buildDoc': [Function],
  toBSON: [Function],
  init: [Function],
  '$hook': [Function: $hook],
  '$pre': [Function: mongoosePreWrapper],
  '$post': [Function: post],
  removePre: [Function: removePre],
  removePost: [Function: removePost],
  _lazySetupHooks: [Function: _lazySetupHooks],
  update: [Function: update],
  '$set': [Function: $set],
  set: [Function: $set],
  '$__shouldModify': [Function],
  '$__set': [Function],
  getValue: [Function],
  setValue: [Function],
  get: [Function],
  '$__path': [Function],
  markModified: [Function],
  unmarkModified: [Function],
  '$ignore': [Function],
  modifiedPaths: [Function],
  isModified: [Function],
  '$isDefault': [Function],
  '$isDeleted': [Function],
  isDirectModified: [Function],
  isInit: [Function],
  isSelected: [Function: isSelected],
  isDirectSelected: [Function: isDirectSelected],
  validate: [Function],
  '$__validate': [Function],
  validateSync: [Function],
  invalidate: [Function],
  '$markValid': [Function],
  '$isValid': [Function],
  '$__reset': [Function: reset],
  '$__dirty': [Function],
  '$__setSchema': [Function],
  '$__getArrayPathsToValidate': [Function],
  '$__getAllSubdocs': [Function],
  '$__handleReject': [Function: handleReject],
  '$toObject': [Function],
  toObject: [Function],
  toJSON: [Function],
  inspect: [Function],
  toString: [Function],
  equals: [Function],
  populate: [Function: populate],
  execPopulate: [Function],
  populated: [Function],
  depopulate: [Function],
  '$__fullPath': [Function]
}
***************************************************
{}

那么我们可以利用mongoose提供的lean()方法,省略去生成完整文档实例,直接返回一个js对象,代码如下:

await ProjectInfos.find(null, { projectName: 1, accountPermissions: 1 })
  .lean()
  .exec((err, docs) => {
    projectList = docs
    console.log("***************************************************");
    console.log(docs[0])
    console.log("***************************************************");
    console.log(docs[0].__proto__)
  })

我们再次打印,如愿得到我们要的结果,同时我们打印出docs[0]的原型,是一个空对象,那么可以证明我们的到docs就是一个js数组,我们可以对每一项的对象进行读写。

***************************************************
{
  _id: 5c13064a3ce9e71c5bdedf29,
  projectName: 'aaa',
  accountPermissions: [
    '5e09a25cd77ad90b2f63cee7',
    '5c0f150f9325280349519b20',
    '5df2f8b330750c2b8f2b8725'
  ]
}
***************************************************
{}

在model文件进行配置

var mongoose = require('mongoose')
mongoose.Promise = require('bluebird')
var schema = mongoose.Schema
var ProjectSchema = new schema({
  id: schema.ObjectId,
  projectName: {type: String, unique: true},
  accountPermissions: Array
)
mongoose.model('ProjectInfo', ProjectSchema)

如果配置完整,我们可以直接得到accountPermissions字段的相关信息,并不需要使用toObject()或者lean()方法。

***************************************************
model {
  '$__': InternalCache {
    strictMode: true,
    selected: { projectName: 1, accountPermissions: 1 },
    shardval: undefined,
    saveError: undefined,
    validationError: undefined,
    adhocPaths: undefined,
    removing: undefined,
    inserting: undefined,
    version: undefined,
    getters: {},
    _id: 5c13064a3ce9e71c5bdedf29,
    populate: undefined,
    populated: undefined,
    wasPopulated: false,
    scope: undefined,
    activePaths: StateMachine {
      paths: [Object],
      states: [Object],
      stateNames: [Array]
    },
    pathsToScopes: {},
    ownerDocument: undefined,
    fullPath: undefined,
    emitter: EventEmitter {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: 0
    },
    '$options': true
  },
  isNew: false,
  errors: undefined,
  _doc: {
    accountPermissions: [
      '5e09a25cd77ad90b2f63cee7',
      '5c0f150f9325280349519b20',
      '5df2f8b330750c2b8f2b8725',
      toBSON: [Function: toBSON],
      _atomics: {},
      _parent: [Circular],
      _cast: [Function: _cast],
      _markModified: [Function: _markModified],
      _registerAtomic: [Function: _registerAtomic],
      '$__getAtomics': [Function: $__getAtomics],
      hasAtomics: [Function: hasAtomics],
      _mapCast: [Function: _mapCast],
      push: [Function: push],
      nonAtomicPush: [Function: nonAtomicPush],
      '$pop': [Function: $pop],
      pop: [Function: pop],
      '$shift': [Function: $shift],
      shift: [Function: shift],
      pull: [Function: pull],
      splice: [Function: splice],
      unshift: [Function: unshift],
      sort: [Function: sort],
      addToSet: [Function: addToSet],
      set: [Function: set],
      toObject: [Function: toObject],
      inspect: [Function: inspect],
      indexOf: [Function: indexOf],
      remove: [Function: pull],
      _path: 'accountPermissions',
      isMongooseArray: true,
      validators: [],
      _schema: [SchemaArray]
    ],
    projectName: 'aaa',
    _id: 5c13064a3ce9e71c5bdedf29
  },
  '$init': true
}
***************************************************
[
  '5e09a25cd77ad90b2f63cee7',
  '5c0f150f9325280349519b20',
  '5df2f8b330750c2b8f2b8725',
  toBSON: [Function: toBSON],
  _atomics: {},
  _parent: model {
    '$__': InternalCache {
      strictMode: true,
      selected: [Object],
      shardval: undefined,
      saveError: undefined,
      validationError: undefined,
      adhocPaths: undefined,
      removing: undefined,
      inserting: undefined,
      version: undefined,
      getters: {},
      _id: 5c13064a3ce9e71c5bdedf29,
      populate: undefined,
      populated: undefined,
      wasPopulated: false,
      scope: undefined,
      activePaths: [StateMachine],
      pathsToScopes: {},
      ownerDocument: undefined,
      fullPath: undefined,
      emitter: [EventEmitter],
      '$options': true
    },
    isNew: false,
    errors: undefined,
    _doc: {
      accountPermissions: [Circular],
      projectName: 'aaa',
      _id: 5c13064a3ce9e71c5bdedf29
    },
    '$init': true
  },
  _cast: [Function: _cast],
  _markModified: [Function: _markModified],
  _registerAtomic: [Function: _registerAtomic],
  '$__getAtomics': [Function: $__getAtomics],
  hasAtomics: [Function: hasAtomics],
  _mapCast: [Function: _mapCast],
  push: [Function: push],
  nonAtomicPush: [Function: nonAtomicPush],
  '$pop': [Function: $pop],
  pop: [Function: pop],
  '$shift': [Function: $shift],
  shift: [Function: shift],
  pull: [Function: pull],
  splice: [Function: splice],
  unshift: [Function: unshift],
  sort: [Function: sort],
  addToSet: [Function: addToSet],
  set: [Function: set],
  toObject: [Function: toObject],
  inspect: [Function: inspect],
  indexOf: [Function: indexOf],
  remove: [Function: pull],
  _path: 'accountPermissions',
  isMongooseArray: true,
  validators: [],
  _schema: SchemaArray {
    casterConstructor: [Function: Mixed] { schemaName: 'Mixed' },
    caster: Mixed {
      path: 'accountPermissions',
      instance: 'Mixed',
      validators: [],
      setters: [],
      getters: [],
      options: {},
      _index: null
    },
    '$isMongooseArray': true,
    path: 'accountPermissions',
    instance: 'Array',
    validators: [],
    setters: [],
    getters: [],
    options: { type: [Function: Array] },
    _index: null,
    defaultValue: [Function]
  }
]

在公司实习的第二个任务,成功踩坑,总结一下,还是要多读文档,不要因为之前的思维习惯而影响新知识的学习。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值