MongoDB 3表设计,非规范化,如何拉和推

时间:2018-11-09 11:33:51

标签: node.js database mongodb express database-design

美好的一天,我已经完成了一个包含三个表的设计,我不确定它是否正确,但是看起来像它可以满足我的需要,而且大多数情况下还可以。我之所以进行非规范化,是因为每个月一次在一个表中(报告)在表中写入数据,而每月一次或可能几次在另一个表(TimeReports)中写入数据,并且每天都会进行读取。

我是否甚至需要进行非规范化,或者ObjectId链接可以解决问题?我可以像按报告一样执行搜索,可以按特定用户查找单个TimeReports和所有TimeReports,所以也许这里不需要非规范化吗?但是我确实需要在报告中显示一些时间报告。

所以我有这个:

let TimeReportSchema = new Schema({
  hours: Number,
  rate: Number,
  sum: Number,
  companyId: {type: mongoose.Schema.Types.ObjectId, ref: 'Company'},
  companyName: String,
  userId: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
  reportId: {type: mongoose.Schema.Types.ObjectId, ref: 'Report'},
  date: {type: Date, default: Date.now},
  updated: {type: Boolean, default: false}
})

let ReportSchema = new Schema({
  userId: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
  director: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
  invoice: {type: String, default: ""},

  time_reports: [TimeReportSchema],

  summary: {type: Number, default: 0},
  date: {
    type: Date,
    default: Date.now
  }
})

var UserSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        unique: true,
        required: true
    },
    ...

    reports: [ReporSchema],

    companyId: {type: mongoose.Schema.Types.ObjectId, ref: 'Company'},
    positionId: {type: mongoose.Schema.Types.ObjectId, ref: 'Position'},
});

我每个月创建一次报表并推入每个用户,而不是用户创建TimeReports,它们还会推到User.reports和Report(本月报表)。

如何从User.reports中删除TimeReport? 如果我可以将报告从用户架构中排除,则仍然存在如何管理更新以及如何从报告中删除TimeReports的问题。

app.delete('/time-report/:id', async (req, res) => {
  let userId;
  await TimeReport.findById(req.params.id, (error, report) => {
    checkForError(res, error);
    userId = report.userId;
    console.log(report, 'report1');
  })
  await TimeReport.remove({
    _id: req.params.id
  }, (error, report) => { 
    checkForError(res, error)
  })
  // User.update({_id: userId}, 
  // {$pull: {'reports.time_reports': {_id: req.params.id}}})
  // res.send({
  //     success: true
  // })
  // that didn't worked
})

app.get('/time-report/:id', (req, res) => {
  let id = req.params.id
  TimeReport.findById(id, (err, reports) => {
    res.send(reports)
  })
})

app.get('/time-reports/:userId', (req, res) => {
  TimeReport.find({userId: req.params.userId}, (err, reports) => {
    console.log(reports, 'reports')
    res.send(reports)
  }).sort({date:-1})
})

app.post('/time-report/:id', async (req, res) => {
  var begin = moment().startOf('month')
  var end = moment(begin).endOf('month')
  let query = {
    userId: req.params.id,
    date: {
      $gte: begin.toDate(),
      $lt: end.toDate()
    }
  }
  let hours = Number(req.body.hours)
  let rate = Number(req.body.rate)
  let sum = hours * rate
  await Report.findOne(query, async (error, report) => {
    console.log(report, 'report for id')
    let reportId = report._id
    newTimeReport = new TimeReport({
      hours, rate, sum, companyId, company, userId, reportId
    })
    newTimeReport.save((error) => {
      checkForError(res, error)
      report.time_reports.push(newTimeReport)
      report.summary += sum
      report.save((error) => {
        checkForError(res, error)
      })
    })
  })

User.findById(req.params.id, (err, user) => {
    user.reports.forEach((report, index) => {
      if(report.date.getMonth() === begin.toDate().getMonth()) {
        report.summary += sum
        report.time_reports.push(newTimeReport)
      }
    })
    user.save((error) => {
      checkForError(res, error)
    })
    res.send(user)
  })

put方法更复杂并且看起来很糟糕。

app.put('/time-report/:id', async (req, res) => {
  let id = req.params.id;
  let reportId;
  let oldSum;
  let newSum;
  TimeReport.findById(id, async (err, report) => {
    reportId = report.reportId
    oldSum = report.sum
    report.hours = Number(req.body.hours)
    report.rate = Number(req.body.rate)
    report.company = req.body.companyName
    report.companyId = req.body.companyId
    report.sum = Number(req.body.hours) * Number(req.body.rate)
    report.updated = true
    report.save((error) => {
    })
    Report.findById(reportId, (error, report) => {
      report.summary -= oldSum
      report.summary += newSum
      for(let j = 0; j < report.time_reports.length; j++) {
        if(report.time_reports[j]._id == id) {
          report.time_reports[j].hours = Number(req.body.hours)
          report.time_reports[j].rate = Number(req.body.rate)
          report.time_reports[j].sum = newSum
        }
      }
      report.save((error) => {
      })
    })
    User.findById(report.userId, (err, user) => {
      loop1:
      for(let i = 0; i < user.reports.length; i++) {
        loop2:
        for(let j = 0; j < user.reports[i].time_reports.length; j++) {
          if(user.reports[i].time_reports[j]._id == id) {
            user.reports[i].summary -= oldSum
            newSum = Number(req.body.hours) * Number(req.body.rate)
            user.reports[i].summary += newSum
            user.reports[i].time_reports[j].hours = Number(req.body.hours)
            user.reports[i].time_reports[j].rate = Number(req.body.rate)
            user.reports[i].time_reports[j].sum = newSum
            user.reports[i].time_reports[j].company = req.body.companyName
            user.reports[i].time_reports[j].companyId = req.body.companyId
            user.reports[i].time_reports[j].updated = true
            break loop1;
          }
        }
      }
      user.save((error) => {
      })
    })
    res.send(report)
  })
})

您能给我一个好的设计建议吗?

0 个答案:

没有答案