Mongoose - REST API - 带有查询到不同模型的模式
Posted
技术标签:
【中文标题】Mongoose - REST API - 带有查询到不同模型的模式【英文标题】:Mongoose - REST API - Schema With Query to different model 【发布时间】:2015-02-13 00:29:42 【问题描述】:我正在尝试避免数据库回调查询。
假设您有两个看起来像这样的模式:
1st) 用户架构
username : type: String, unique: true,
age : type: Number
2nd) 活动架构
owner: [type: Schema.Types.ObjectId, ref: 'User'],
city: type: String,
date: type: Date
到目前为止一切顺利。
现在假设您有一条到/user/:id
的路线,您希望得到username
和age
,但是如果我还想在该路线上返回最新活动怎么办?
编辑:请注意latest activity
不是数据库中的值。它是像activity.find(owner: ObjectId(id)).sort(date: -1).limit(1)
一样自动计算的
现在做了什么:
User.findOne(username:req.params.username).lean().exec(function(err,userDoc)
if(err) return errHandler(err);
Activity.findOne(owner:userDoc.username).sort(date:-1).exec(function(err,EventDoc)
if(err) return errHandler(err);
userDoc.latest_activity = EventDoc._id;
res.json(userDoc);
res.end();
)
)
上面sn-p的问题是很难维护, 如果我们想为这个 API 功能添加更多内容怎么办?除非我们实现 Q,否则我们将在查询地狱般的回调中结束。
我们尝试查看虚拟,但问题是您不能 真正在 mongoose Virtual 中查询,因为它返回一个 竞争条件,您很可能无法按时获得该文件。
我们也尝试查看 populate,但由于有关 populate 的文档非常糟糕,我们无法做到。
问题: 有没有办法让它更加模块化?
有什么办法可以避免地狱的数据库查询回调?
例如这种事情可能吗?
User.findOne(username:req.params.username).lean().populate(
path:'Event',sort:Date:-1, limit(1)
).exec(function(req,res))...
谢谢!
【问题讨论】:
我又更新了一遍,应该更清楚了。我认为没有人解决这个问题是荒谬的。 您正在执行手动联接。该空间中似乎有许多模块:npmjs.com/search?q=mongo+join(或者如果您确实有关系数据,请使用关系数据库) 所以你在这里说的是,如果我试图构建一个 REST API 路由来返回文档旁边的额外数据(对不同集合的查询),则无法避免回调地狱除非我使用 RDBMS,否则查询,对吗?必须有另一种方法.. mongoose 中的功能架构设计populate
仅适用于包含 ref 的模型(在本例中为 Activity
)。因此,您可以获取用户的最新活动并填充其owner
数组,但反之则不行。
您可以通过多种方式避免回调地狱,例如异步模块、承诺等。 . .但是,如果您花时间手动加入集合,那就错了。另一种选择是布置您的数据,以便您不需要加入它,例如当活动发生时使用 last_activity 更新用户。
【参考方案1】:
受@BrianShambien 的回答的启发,您可以使用帖子保存,但不是仅将_id
存储在用户上,而是仅存储最后一个活动的子文档。然后,当您抓住该用户时,它就在那里有最后一个活动。
用户模型
username : type: String, unique: true,
age : type: Number,
last_activity: ActivitySchema
然后你在你的ActivitySchema
上做一个post save hook
ActivitySchema.post('save', function(doc)
UserSchema.findOne(username: doc.owner).exec(function(err, user)
if (err) errHandler(err);
user.last_activity = doc;
user.save(function(err)
if (err) errHandler(err);
);
);
);
**********更新************
如果用户不是所有者,而是活动的参与者,这将包括对用户的更新。
ActivitySchema.post('save', function(doc)
findAndUpdateUser(doc.owner, doc);
if (doc.participants)
for (var i in doc.participants)
findAndUpdateUser(doc.participants[i], doc);
);
var findAndUpdateUser = function (username, doc)
UserSchema.findOne(username: username).exec(function (err, user)
if (err) errHandler(err);
user.last_activity = doc;
user.save(function (err)
if (err) errHandler(err);
);
);
);
【讨论】:
与 Brian 的回答太相似了,但是看看我写的评论,如果你能解决这个问题,那就太棒了。 类似是的,但是他仍然会要求您进行第二次查询以获取最新活动。我的只需要你拉用户,因为最新的活动将在用户身上 这更有意义,我更新了我的答案。你是这个意思吗?【参考方案2】:在这种情况下,最好的处理方法是向您的Activity
架构添加一个保存后挂钩,以将最新的_id
存储在您的latest_activity
架构的latest_activity
路径中。这样您就可以随时访问 id 而无需进行额外的查询。
ActivitySchema.post('save', function(doc)
UserSchema.findOne(username: doc.owner).exec(function(err, user)
if (err)
console.log(err); //do something with the error
else if (user)
user.latest_activity = doc._id;
user.save(function(err)
if (err)
console.log(err); //do something with the error
);
);
);
【讨论】:
您是否还需要进行额外的查询,无论是通过_id
还是user._id
搜索活动?
在您的原始示例中,您只是将 _id 值分配给 latest_activity,从而获得了相同的结果。使用我的方法,如果需要,您仍然需要加载活动详细信息,就像您在示例中所做的那样,但它消除了每次查找最新 _id 的昂贵排序查询的需要。
总结你的答案:你建议布局数据,在用户架构中添加最新的活动,这将根据“保存”钩子更新最新的活动?这很好,但是,如果最新的活动有点复杂怎么办?例如 latest_activity = 所有者或参加了活动? (问题中没有提到这个,我只是想更好地理解)。填补空白,您将成为英雄
@Linial 我在这里有点困惑,Brian Shambien 的示例确实可以处理任何复杂的情况。它将为您提供用户参与的活动的参考。他的示例缩短了查询时间,就像他说它从查找查询中删除了排序一样。你能解释一下“有点复杂”是什么意思吗?
例如:最新活动 = db.activity.find($or:[owner:username,participated:$in:[username]]).sort(date:-1).limit(1)
这意味着最新活动是拥有或参与的活动的组合,并且从最新到最新排序。以上是关于Mongoose - REST API - 带有查询到不同模型的模式的主要内容,如果未能解决你的问题,请参考以下文章
不使用 API REST MEAN + Mongoose 中的方法“UPDATE”
用于 rest api 的 typegoose/mongoose 日期格式
单元/集成测试 Express REST API, mongoose, mocha, sinon, chai, supertest
如何对使用 Express + Mongoose 构建的 NodeJs REST API 服务器进行单元测试?