【问题标题】:MongoDB query on populated fieldsMongoDB 查询填充字段
【发布时间】:2013-11-03 13:39:23
【问题描述】:

我有我正在查询的名为“活动”的模型(使用 Mongoose)。他们的架构如下所示:

var activitySchema = new mongoose.Schema({
    actor: {
        type: mongoose.Schema.ObjectId,
        ref: 'User',
        required: true
    },
    recipient: {
        type: mongoose.Schema.ObjectId,
        ref: 'User'
    },
    timestamp: {
        type: Date, 
        default: Date.now
    },
    activity: {
        type: String,
        required: true
    },
    event: {
        type: mongoose.Schema.ObjectId,
        ref: 'Event'
    },
    comment: {
        type: mongoose.Schema.ObjectId,
        ref: 'Comment'
    }
});

当我查询它们时,我正在填充 actorrecipienteventcomment 字段(所有引用)。之后,我还深度填充了event 字段以获取event.creator。这是我的查询代码:

var activityPopulateObj = [
                { path: 'event' },
                { path: 'event.creator' },
                { path: 'comment' },
                { path: 'actor' },
                { path: 'recipient' },
                { path: 'event.creator' }
            ],
            eventPopulateObj = {
                path: 'event.creator',
                model: User
            };

Activity.find({ $or: [{recipient: user._id}, {actor: {$in: user.subscriptions}}, {event: {$in: user.attending}}], actor: { $ne: user._id} })
            .sort({ _id: -1 })
            .populate(activityPopulateObj)
            .exec(function(err, retrievedActivities) {
                if(err || !retrievedActivities) {
                    deferred.reject(new Error("No events found."));
                }
                else {
                    User.populate(retrievedActivities, eventPopulateObj, function(err, data){
                        if(err) {
                            deferred.reject(err.message);
                        }
                        else {
                            deferred.resolve(retrievedActivities);
                        }
                    });
                }
            });

这已经是一个相对复杂的查询,但我还需要做更多。如果遇到$or 语句中的{actor: {$in: user.subscriptions}} 部分,我需要确保eventprivacy 字段等于字符串public。我尝试使用$elemMatch,但由于必须先填充事件,我无法查询它的任何字段。我也需要在其他多个查询中实现同样的目标。

我有什么办法可以像我描述的那样实现进一步的过滤吗?

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:

    但由于必须先填充事件,所以我无法查询它的任何字段。

    没有办法。 Mongodb 不能做连接。进行查询时,您一次只能使用一个集合。仅供参考,所有这些 mongoose 填充都是额外的、不同的数据库查询来加载这些记录。

    我没有时间深入了解您的架构和应用程序的详细信息,但您很可能需要对数据进行非规范化并将您需要加入的任何事件字段的副本存储在主集合中。

    【讨论】:

      【解决方案2】:

      答案是改变你的架构。

      从使用关系数据库的历史开始,当您进入文档数据库开发时,您已经陷入了许多开发人员在您之前遇到的陷阱:MongoDB 不是一个关系数据库,不应该被视为一个。

      您需要停止考虑外键和完全规范化的数据,而是尽可能保持每个文档自包含,考虑如何最好地将相关的关联数据嵌入到您的文档中。

      这并不意味着您也不能保持关联。这可能意味着这样的结构,您只嵌入必要的详细信息,并在需要时查询完整记录:

      var activitySchema = new mongoose.Schema({
        event: {
          _id: { type: ObjectId, ref: "Event" },
          name: String,
          private: String
        },
      
        // ... other fields
      });
      

      重新考虑您的嵌入策略将极大地简化您的查询并将查询计数保持在最低限度。 populate 会迅速增加您的计数,并且随着您的数据集的增长,这很可能会成为一个问题。

      【讨论】:

      • 你说得对,我想除了查询参考之外,我还必须有一些单独的字段。谢谢!
      • 回答时可能不存在,但填充方法支持“匹配”属性:populate({ path: 'notes', match: /airline/, select: 'text', model: 'modelName' options: opts }).mongoosejs.com/docs/api.html#document_Document-execPopulate
      • 感谢@DougMolineux。但是,如果我在填充之前使用 find 方法,那么它会给我 null 填充匹配属性不成立的地方。有什么解决办法吗?
      【解决方案3】:

      您可以尝试以下聚合。看看这个答案:https://stackoverflow.com/a/49329687/12729769

      然后,您可以在查询中使用 $addFields 中的字段。喜欢

      {score: {$gte: 5}}

      【讨论】:

      • 您好。可以将基于链接的答案设为 cmets。
      猜你喜欢
      • 2021-02-16
      • 2013-07-06
      • 2015-01-10
      • 2021-03-03
      • 2021-11-03
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      相关资源
      最近更新 更多