猫鼬:加强友谊关系,回报用户的朋友

时间:2015-09-04 00:51:46

标签: node.js mongodb mongoose

我正在尝试在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)中,但我仍然遇到同样的错误。

1 个答案:

答案 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”。