我有要查询的模型(称为“活动”)(使用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' } });
当我询问他们,我填充actor,recipient,event,和comment字段(所有引用)。在那之后,我也深入了这个event领域event.creator。这是我的查询代码:
actor
recipient
event
comment
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}},我 还 需要确保event的privacy字段等于字符串public。我尝试使用$elemMatch,但是由于必须先填充事件,因此无法查询其任何字段。我还需要在其他多个查询中实现相同的目标。
$or
{actor: {$in: user.subscriptions}}
privacy
public
$elemMatch
如我所描述的,我有什么办法实现这种进一步的过滤?
答案是更改架构。
从使用关系数据库的历史开始进行文档数据库开发时,您已经陷入许多开发人员面前的陷阱:MongoDB不是关系数据库,不应被视为一个。
您需要停止考虑外键和完美标准化的数据,而应使每个文档尽可能保持独立,并考虑如何在文档中最好地嵌入相关数据。
这并不意味着您也无法维护关联。它可能意味着这样的结构,其中您仅嵌入必要的详细信息,并在需要时查询完整记录:
var activitySchema = new mongoose.Schema({ event: { _id: { type: ObjectId, ref: "Event" }, name: String, private: String }, // ... other fields });
重新考虑您的嵌入策略将 极大地 简化查询,并将查询数量保持在最低水平。 populate会使您的人数迅速增加,并且随着数据集的增长,这很可能会成为问题。
populate