【问题标题】:mongoose - How to get an object instead of an object reference in a getter?mongoose - 如何在 getter 中获取对象而不是对象引用?
【发布时间】:2018-07-08 03:46:39
【问题描述】:

我在 Node.js 中使用 mongoose 创建了一个 API。我将我的数据保存在一个集合 Transactions 中,它提供了来自其他集合对象的一些引用:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const transactionSchema = new Schema({
  status: String,
  _user: { type: Schema.Types.ObjectId, ref: 'User' },
  _borne: { type: Schema.Types.ObjectId, ref: 'Borne' },
  createdAt: Date,
  updatedAt: Date
});

当我对事务进行查询时,我会得到 Borne 对象而不是它的 id,因为它保存在我的数据库中。我不直接将其保存为 Borne 对象,因为我的 Borne(或 User)对象中可能会出现一些更改,我希望将其保存在每个 Transaction 对象上。

所以我尝试使用虚拟或路径(覆盖),但它不会改变我的输出,我也不知道这样做是否正确:

// In this example, I try to change the status output by "new status" to test if it works, and it doesn't
transactionSchema.path('status')
    .get(function(value) {
        return "new status";
    })
});

输出与之前相同。


编辑:Populate 是解决方案,但不起作用

目前,我正在将我的模型加载到我的 index.js 文件中:

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const apn = require('apn');
const keys = require('./config/keys');

require('./app/models/Borne');
require('./app/models/User');
require('./app/models/Transaction');
require('./app/models/Comment');
require('./app/models/Notification');

const app = express();

const apnProvider = new apn.Provider(keys.apns.options);

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

mongoose.connect(keys.mongoURI, (err, database) => {
  if (err) return console.log(err);

  require('./app/routes')(app);

  const PORT = process.env.PORT || 8000;
  app.listen(PORT, () => {
    console.log('We are live on ' + PORT);
  });
});

那么,这里是一个模型的例子:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const transactionSchema = new Schema({
  status: String,
  details: {
    amount: { type: Number }, // money
    quantity: { type: Number }, // power consumed
    date: { type: Date },
    city: { type: String }
  },
  logs: [
    {
      state: String,
      date: Date
    }
  ],
  _user: { type: Schema.Types.ObjectId, ref: 'User' },
  _borne: { type: Schema.Types.ObjectId, ref: 'Borne' },
  createdAt: Date,
  updatedAt: Date
});

mongoose.model('transactions', transactionSchema);

最后,这里是我称之为populate 的地方。它不起作用:

const mongoose = require('mongoose');

const User = mongoose.model('users');
const Transaction = mongoose.model('transactions');
const Borne = mongoose.model('bornes');
const Comment = mongoose.model('comments');

module.exports = app => {
    app.get('/v1/user/:id/transactions', async (req, res) => {
        const ObjectID = require('mongodb').ObjectID;

        var id = req.params.id;
        var existingUser;
        if (req.params.id == 'me' && req.user) {
            id = req.user.id;
            existingUser = req.user;
        } else {
            existingUser = await User.findOne({ _id: new ObjectID(id) });
        }

        if (existingUser) {
            const transactions = await Transaction.find({
                _user: new ObjectID(id),
                status: { $nin: ['booked', 'charging', 'charged', 'left'] }
            }).populate('_user').populate('_borne').sort({ updatedAt: -1 });

            // ...

            res.status(200);
            res.send({
                statusCode: 200,
                data: transactions
            });
        }
    });
};

【问题讨论】:

    标签: javascript node.js mongodb mongoose mongoose-schema


    【解决方案1】:

    根据MongoDB Documentation,如果要获取引用指向的对象,则必须“手动”进行第二次查询。

    但是Mongoose 提供了populate 方法,它允许您将引用替换为正确的文档。

    填充是自动替换指定的过程 文档中的路径以及来自其他集合的文档。

    所以,在你的情况下,你可以这样做:

    var transactionModel = mongoose.model('Transaction', transactionSchema);
    
    transactionModel
      .find({})
      .populate('_user')
      .populate('_borne')
      .exec((err, transaction) => {
        if (err) return handleError(err);
        // deal with your transaction
      });
    


    编辑

    我刚刚看了你的编辑,你能帮我试试吗:

    删除您的index.js 文件中的所有require('./app/models/xxx')

    在你的模型结束时:

    module.exports = mongoose.model('xxx', xxxSchema);
    

    然后在你的路由/控制器中:

    const User = require('/app/models/users');
    const Borne = require('/app/models/borne');
    const Transaction = require('/app/models/transaction');
    

    因此,您的模型与架构是同时创建的,并且您确定这是正确的顺序。

    希望对你有帮助,
    最好的问候

    【讨论】:

    • 你有没有报错,一条信息说一些特别的东西,上面的代码在你尝试的时候是什么行为?
    • 我收到了错误:MissingSchemaError: Schema hasn't been registered for model "User"
    • 嗯,这是另一个问题,它来自您为用户集合所做的参考:_user: { type: Schema.Types.ObjectId, ref: 'User' }。它说没有模型“用户”的模式,这是制作 ref 所必需的。这可能是因为包含您的用户架构的文件在包含您的事务架构的文件中没有被解释(如this answer 中所建议的那样)
    • 我更新了我的问题,详细说明了为什么它不起作用。对你帮助我有帮助吗?
    • 不行,我们可以聊聊吗?会更容易
    【解决方案2】:

    我认为要有一个快速而健壮的查询,你应该看看 Aggregate Query with moongodb。

    查询事务集合(匹配正确的_id),然后展开_user属性,查找用户集合(类似于SQL中的JOIN),展开_born集合,查找出生集合。

    这样看起来有点复杂,但它非常强大和快速。

    【讨论】:

      猜你喜欢
      • 2021-02-11
      • 2020-09-12
      • 2018-09-22
      • 2016-01-23
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      • 1970-01-01
      相关资源
      最近更新 更多