返回不在模型

时间:2018-04-09 09:08:48

标签: node.js mongodb mongoose

我有projects存储batches条记录。使用mongoose从我的mongoDB中检索project时,我想计算属于该特定项目的批次数。

我的项目模型架构目前如此:

const schema = new Schema({
  name: {
    type: String,
    required: true,
    unique: true
  },
  slug: {
    type: String,
    required: true,
    unique: true
  }
}, {
  timestamps: true
})

我的批量模型架构看起来:

const schema = new Schema({
  project:{
    type: ObjectId,
    ref: 'Project',
    required: true
  },
  file: {
    type: String,
    required: true
  },
  orginal_name: {
    type: String,
    required: true
  }
}, {
  timestamps: true
})

我有一个函数,它根据batch.project字段计算属于项目的批次数,然后将其添加到项目的JSON对象(例如project.batchCount)。但是我遇到了一个问题,即由模型toJSON或toObject函数删除新字段project.batchCount,因为该字段在模型模式中不存在。

我目前的解决方案是将它作为'虚拟字段'添加到模型模式中,它永远不会保存到mongoDB中:

const schema = new Schema({
  name: {
    type: String,
    required: true,
    unique: true
  },
  slug: {
    type: String,
    required: true,
    unique: true
  },
  batchCount: {
    type: Number
  }
}, {
  timestamps: true
})

但是我不喜欢这种方式,因为它使我的模型比需要的更大,而且“可读性”稍差。

有更好的方法吗?如果是这样的话?

1 个答案:

答案 0 :(得分:1)

我认为你所寻找的是模式上的虚拟。 mongoose上的文档上的虚拟文件在本地可用,但不会保存到数据库中。

我喜欢在架构上使用静态来获取项目计数的想法。我也喜欢在文档而不是模型上调用方法的想法,所以我在实例方法中实现了它。静态也会起作用。这取决于您的偏好。

以下是我提出的建议:

<强> batch.js

'use strict';

const mongoose = require('mongoose');
const Schema = mongoose.Schema;


const batchSchema = new Schema({
  project: {
    type: Schema.Types.ObjectId,
    ref: 'Project',
    required: true
  },
  file: {
    type: String,
    required: true
  },
  original_name: {
    type: String,
    required: true
  }
}, {
  timestamps: true
});

batchSchema.virtual('projectCount')
  .get(function () {
    return this._projectCount;
  })
  .set(function (v) {
    this._projectCount = v;
  });

batchSchema.methods.count = async function () {
  let found = await this.model('Batch').count({ project: this.project });
  this._projectCount = found;
};


const Batch = mongoose.model('Batch', batchSchema);

module.exports = Batch;

虚拟调用projectCount有一个简单的setter和getter,如果需要,可以覆盖该值,或者在设置后检索它。

每个文档的实例方法称为count(),并使用查询当前文档的项目_id来调用Model.count()方法。

<强> project.js

'use strict';

const mongoose = require('mongoose');
const Schema = mongoose.Schema;


const projectSchema = new Schema({
  name: {
    type: String,
    required: true,
    unique: true
  },
  slug: {
    type: String,
    required: true,
    unique: true
  }
}, {
  timestamps: true
});

const Project = mongoose.model('Project', projectSchema);

module.exports = Project;

<强> populate.js

#!/usr/bin/env node
'use strict';

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const conn = mongoose.connection;
const Batch = require('./batch');
const Project = require('./project');

const projects = [];
const batches = [];

for (let i = 0; i < 10; i++) {
  const project = new Project({
    name: `project${i}`,
    slug: `slug${i}`
  });
  for (let j = 0; j < 10; j++) {
    const batch = new Batch({
      project: project._id,
      file: `file${j}`,
      original_name: `name${j}`
    });
    batches.push(batch);
  }
  projects.push(project);
}

async function add () {
  await conn.dropDatabase();
  const savedProjects = await Project.create(projects);
  const savedBatches = await Batch.create(batches);
  console.log(`Added ${savedProjects.length} projects.`);
  console.log(`Added ${savedBatches.length} batches.`);
  return conn.close();
}

add();

populate.js就是我为这个例子创建集合和文档的方式,这里没什么特别的。

<强> get.js

#!/usr/bin/env node
'use strict';

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const conn = mongoose.connection;
const Batch = require('./batch');

async function get () {
  let f = await Batch.findOne({});
  await f.count();
  console.log(`the project for this batch has ${f.projectCount} matches`);
  return conn.close();
}

get().catch(console.error);

调用实例方法count()后,我们可以访问存储在虚拟projectCount中的值。

bash输出

49729301: ./populate.js
Added 10 projects.
Added 100 batches.
49729301: ./get.js
the project for this batch has 10 matches
49729301:

mongo shell输出

49729301: mongo --quiet test
> db.batches.findOne()
{
        "_id" : ObjectId("5acbbebb4cd320cb4e403e8f"),
        "project" : ObjectId("5acbbebb4cd320cb4e403e8e"),
        "file" : "file0",
        "original_name" : "name0",
        "createdAt" : ISODate("2018-04-09T19:27:55.395Z"),
        "updatedAt" : ISODate("2018-04-09T19:27:55.395Z"),
        "__v" : 0
}
>

如您所见,虚拟属性仅在本地可用,并且不会存储在数据库中。