我正在尝试在mongoose中为我的用户架构添加一个实例方法,该方法返回用户与之友好的其他用户的集合。
用户架构:
var User = new Schema({
username : String,
password: String
});
友谊架构:
var FriendShip = new Schema({
user_id: String,
friend_id: String,
accepted: Boolean
});
我创建了两个方法来返回用户的朋友_id
// Return id of users that are friends of this instance
User.methods.myFriendsId = function () {
var friendship = this.model('Friend').find({user_id: this._id, accepted: true});
var friends_id = {};
for (f of friendship) {
friends_id[friends_id.length] = f.friend_id;
}
return friends_id;
};
// Returns id of users that have this instance as friend
User.methods.friendOfId = function () {
var friendship = this.model('Friend').find({friend_id: this._id, accepted: true});
var friends_id= {};
for (f of friendship) {
friends_id[friends_id.length] = f.user_id;
}
return friends_id;
};
然后我有了应该归还朋友的方法
我.concat()
两种方法的结果然后尝试遍历friends_id
以找到每个用户。
User.methods.friends = function () {
var friends_id = this.myFriendsId().concat(this.friendOfId());
var friends = {};
for (id of friends_id) {
this.model('User').findById(id, function(err, user) {
friends[friends.length] = user;
});
}
return friends;
};
我想在user.friends()
个实例上拨打user
时收到一些朋友。
修改
嗨@Reto,很抱歉这么晚回到你身边,我正在学习我的空闲时间节点,而且我没有那么多。
感谢您的建议,我现在已经了解了Nodejs异步调用是如何工作的,我也了解了mongodb的承诺,并且我只是通过说“变量等于承诺”而得不到任何回报。 var friends_id = User.find();
。虽然我最初试图避免传递回调,因为我希望能够在ejs
视图中调用该方法,我发现这是不可能的,所以我找到了更好的方法将数据传递给我的视图。我还学习了如何编写更好的mongodb查询,而不是为id
数组中的每个friends_id
命中数据库。
正如你正确地指出我只是用节点和JavaScript测试水域,我来自C#背景。所以这就是我所做的。
我修改了Friendship
架构,将_id
(s)存储为ObjectId
而不是String
。
var Friendship = new Schema({
user_id: Schema.ObjectId,
friend_id: Schema.ObjectId,
accepted: Boolean
});
我已经摆脱了那些返回friends_id
的函数,因为调用必须是异步的。所以我的User.methods.friends
函数现在看起来像这样。
User.methods.friends = function (callback) {
var id = this._id;
return this.model('Friendship').find({$or: [
{user_id: id}, // check if id is in user_id column
{friend_id: id} // check if id is in friend_id column
]},
function (err, friendships) {
if (err) return err;
var friends_id = friendships.map(function (f) { // This forms an array of whatever you return from it.
return (id.toString() !== f.user_id.toString()) ?
f.user_id : f.friend_id; // return user_id or friend_id if it does not belong to this user.
});
this.model('User').find({_id: {$in: friends_id}}, callback);
});
};
但我有一个新问题,我在这里得到TypeError
:
this.model('User').find({_id: {$in: friends_id}}
。
if (obj && '_id' in obj) continue;
^
TypeError: Cannot use 'in' operator to search for '_id' in User
我在mongodb控制台中尝试了这个,用户按预期返回。
db.users.find({_id: {$in : [
new ObjectId("55f802d3020b2641028819ba"),
new ObjectId("55f80281cf08f091062f9f4c")
]}})
我查了一下这个错误,我发现的不适用于我。答案是将friends_id
解析为JSON对象,但不需要,因为我直接从查询中获取它。
我尝试转换_id
(s).toString()
或将它们包装在new ObjectId(_id)
中,但我仍然遇到同样的错误。
答案 0 :(得分:0)
您的方法存在很多问题 - 主要问题是您似乎没有遵循node.js异步执行模型的基本原则。 这与Java等其他编程语言中的典型代码非常不同:
var friends_id = this.model('Friend').find({user_id: this._id, accepted: true});
这不会返回朋友列表!它返回您仍需要执行的查询或承诺对象。您将需要向其传递一个回调方法,该方法将在数据库查询完成时调用。
您无法在node.js中的模型上编写方法,该方法在同步查询数据库后返回朋友列表。您只能编写一个采用Callback方法并且不返回任何内容的方法。然后,它将在DB查询完成时执行回调,并将结果列表作为参数传递给回调方法。
首先尝试使用更简单的示例深入了解node.js编程,并确保完全理解异步编程的工作原理,回调是什么,也许可以研究“Promises”。