对填充字段的 MongoDB 查询

MongoDB query on populated fields

本文关键字:MongoDB 查询 字段 填充      更新时间:2023-09-26

我有一个名为"活动"的模型,我正在查询(使用猫鼬)。它们的架构如下所示:

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 ,但由于必须先填充事件,因此我无法查询其任何字段。我还需要在多个其他查询中实现相同的目标。

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

答案是更改架构。

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

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

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

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

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

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

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

{score: {$gte: 5}}

但由于必须首先填充事件,因此我无法查询其任何字段。

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

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