$ inc follower count,或者我应该使用聚合来跟踪它们?

Noo*_*ter 6 javascript mongoose mongodb node.js

我通过无限卷轴一次装入12个大块的产品.

有时,我可能想根据他们有多少粉丝对这些进行排序.

以下是我如何跟踪每个产品有多少粉丝.


由于16mb的数据上限,以下是单独的集合,并且下面的数量应该是无限的.

遵循架构:

var FollowSchema = new mongoose.Schema({
    user: {
        type: mongoose.Schema.ObjectId,
        ref: 'User'
    },
    product: {
        type: mongoose.Schema.ObjectId,
        ref: 'Product'
    },
    timestamp: {
        type: Date,
        default: Date.now
    }
});
Run Code Online (Sandbox Code Playgroud)

遵循架构的产品:

var ProductSchema = new mongoose.Schema({
    name: {
        type: String,
        unique: true,
        required: true
    },
    followers: {
        type: Number,
        default: 0
    }
});
Run Code Online (Sandbox Code Playgroud)

每当用户关注/取消关注产品时,我都会运行此功能:

ProductSchema.statics.updateFollowers = function (productId, val) {
    return Product
        .findOneAndUpdateAsync({
            _id: productId
        }, {
            $inc: {
                'followers': val
            }
        }, {
            upsert: true,
            'new': true
        })
        .then(function (updatedProduct) {
            return updatedProduct;
        })
        .catch(function (err) {
            console.log('Product follower update err : ', err);
        })
};
Run Code Online (Sandbox Code Playgroud)

我对此有疑问:

1:产品中增加的"跟随者"值是否有可能遇到某种错误,导致数据不匹配/不一致?

2:为每个产品编写一个聚合来计算关注者会更好吗,还是会太昂贵/慢?

最终,我可能会在graphDB中重写它,因为它似乎更适合,但是现在 - 这是掌握MongoDB的练习.

gzc*_*gzc 0

1 如果插入后递增或删除后递减,则有可能导致数据不一致。例如,插入成功但递增失败。

2 直观上,在这种情况下,聚合比查找要昂贵得多。我做了一个基准测试来证明这一点。

首先随机生成1000个用户、1000个产品和10000个关注者。然后,使用此代码进行基准测试。

import timeit

from pymongo import MongoClient
db = MongoClient('mongodb://127.0.0.1/test', tz_aware=True).get_default_database()

def foo():
    result = list(db.products.find().sort('followers', -1).limit(12).skip(12))

def bar():
    result = list(db.follows.aggregate([
        {'$group': {'_id': '$product', 'followers': {'$sum': 1}}},
        {'$sort': {'followers': -1}},
        {'$skip': 12},
        {'$limit': 12}
    ]))

if __name__ == '__main__':
    t = timeit.timeit('foo()', 'from __main__ import foo', number=100)
    print('time: %f' % t)

    t = timeit.timeit('bar()', 'from __main__ import bar', number=100)
    print('time: %f' % t)
Run Code Online (Sandbox Code Playgroud)

输出:

time: 1.230138
time: 3.620147
Run Code Online (Sandbox Code Playgroud)

创建索引可以加快查找查询速度。

db.products.createIndex({followers: 1})

time: 0.174761
time: 3.604628
Run Code Online (Sandbox Code Playgroud)

如果您需要产品的属性(例如名称),则需要另一个 O(n) 查询。

我猜当数据规模扩大时,聚合会慢得多。如果需要,我可以对大规模数据进行基准测试。