关于node.js:聚合后用猫鼬更新集合

updating collection with mongoose after an aggregation

我目前正在一家小型公司工作,担任实习生,并且正在开发类似如下的用户架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
var UserSchema = new Schema({
    name: String,
    email: {
        type: String,
        unique: true
    },
    username: {
        type: String,
        unique: true
    },
    hashed_password: String,
    provider: String,
    salt: String,

,由于我正在处理的应用程序发生更改,因此我更新了此架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var UserSchema = new Schema({
    name: String,
    email: {
        type: String,
        unique: true
    },
    username: {
        type: String,
        unique: true
    },
    hashed_password: String,
    provider: String,
    salt: String,


    stats : {
        bricks: Number,// Number of bricks created by an user
        layers: Number,// --------- layers ------------------
        projects: Number,//-------- projects ----------------
        lastogin: Date
    },

});

当然,在线存在该应用程序的旧版本,我需要更新用户集中现有的所有用户。

为此,我需要计算每个用户创建的每个砖块/层/项目。这是砖模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**************
App fields
**************/

// False deletion field
field.deleted = function() {
  return field.bool();
};

// Creation date
field.created = function() {
  return field.date();
};

// Title Field
field.title = function() {
  return field.string();
};

// Desc Field
field.desc = function() {
  return field.string();
};

// Default short Id field
field.shortId = function(id) {
  return {
    type: ShortId,
    index: true,
    len: 7,     // Length 7 characters
    base: 64,   // Web-safe base 64 encoded string
    alphabet:"abcdefghijklmnopkrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", // Use default alphabet for base
    retries: 4  // Four retries on collision
  };
};

// The author of the content
field.user = function() {
  return {
    user: field.ref('User'),
  }
};

field.favorites = function() {
  return [{
    type: Schema.ObjectId,
    ref: 'User'
  }];
};

field.contributors = function() {
  return [{
    type: Schema.ObjectId,
    ref: 'User'
  }];
};

field.comments = function() {
  return [{
    // user that have written the comment
    user: field.ref('User'),
    // comment text it-self
    comment: field.string()
  }];
};

经过一番研究,我决定使用mongoose(和mongodb)的聚合管道根据用户使用以下查询对砖进行分组:

1
2
3
4
5
6
7
8
9
db.bricks.aggregate(
    [
        {
            $group : {
                _id :"$user",
                count : {  $sum : 1}
        }
    ]
)

以及以下使用猫鼬的方法:

1
2
3
4
5
6
7
8
var promise =Brick.aggregate()
        .group({ _id:"$user"})
        .exec(function (err, res) {
            if (err) return handleError(err);
            else {
                console.log(res);
            }
        });

我知道exec()方法会返回一个promise,但我仍在学习如何正确使用它。

之后,我想对所有用户执行更新查询。由于它们没有创建相同数量的积木,因此我无法进行多次更新,因此需要使用如下查询循环遍历结果:

1
User.update({id : user_id}, {$set : {"stats.bricks" : Brick.find({user : user_id}).count()}})

是否可以通过这种方式做到?还是我需要以其他方式重新思考问题?


我尝试了其他方法,并成功获得了想要的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
exports.updatesUsersStats = function (req, res) {
  User.find().exec(function(err, users) {
    console.log(users.length);
    _.each(users, function(currentUser) {
      console.log("Count bricks user :" +currentUser._id);
      Brick.find({user : currentUser._id})
        .exec(function(err, bricks) {
          if(err) return handleError(err);
          console.log("Update user :"+ currentUser._id);
          User.update({_id : currentUser._id}, {$set : {"stats.bricks" : bricks.length}})
            .exec(function(err)
            {
              if(err) return handleError(err);
            });
        });
    });
    res.jsonp({
      updateType :"updateUserStats",
      operations : users.length
    });
  });
};

我撇开了考虑所有用户(未创建内容的用户)的聚合。