From 7472cf2b169271f1a4105eab0eadd43a6b532cf2 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Fri, 17 Mar 2017 10:46:29 +0100 Subject: [PATCH] Properly count Blender Sync users Use a dedicated aggregation pipeline to filter one startup.blend per home project and count them. --- cloud/stats/__init__.py | 92 +++++++++++++++++++++++++++++------------ cloud/stats/routes.py | 7 +--- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/cloud/stats/__init__.py b/cloud/stats/__init__.py index 22d693e..3c18ab0 100644 --- a/cloud/stats/__init__.py +++ b/cloud/stats/__init__.py @@ -2,35 +2,34 @@ from flask import current_app -pipeline = [ - {'$match': {'_deleted': {'$ne': 'true'}}}, - { - '$lookup': - { - 'from': "projects", - 'localField': "project", - 'foreignField': "_id", - 'as': "project", - } - }, - { - '$unwind': - { - 'path': '$project', - } - }, - { - '$project': - { - 'p.is_private': 1, - } - }, - {'$match': {'p.is_private': {'$ne': True}}}, - {'$count': 'tot'} -] - def count_nodes(query=None) -> int: + pipeline = [ + {'$match': {'_deleted': {'$ne': 'true'}}}, + { + '$lookup': + { + 'from': "projects", + 'localField': "project", + 'foreignField': "_id", + 'as': "project", + } + }, + { + '$unwind': + { + 'path': '$project', + } + }, + { + '$project': + { + 'p.is_private': 1, + } + }, + {'$match': {'p.is_private': {'$ne': True}}}, + {'$count': 'tot'} + ] c = current_app.db()['nodes'] # If we provide a query, we extend the first $match step in the aggregation pipeline with # with the extra parameters (for example node_type) @@ -45,3 +44,42 @@ def count_nodes(query=None) -> int: def count_users() -> int: u = current_app.db()['users'] return u.count() + + +def count_blender_sync() -> int: + pipeline = [ + # 0 Find all startups.blend that are not deleted + { + '$match': { + '_deleted': {'$ne': 'true'}, + 'name': 'startup.blend', + } + }, + # 1 Group them per project (drops any duplicates) + {'$group': {'_id': '$project'}}, + # 2 Join the project info + { + '$lookup': + { + 'from': "projects", + 'localField': "_id", + 'foreignField': "_id", + 'as': "project", + } + }, + # 3 Unwind the project list (there is always only one project) + { + '$unwind': + { + 'path': '$project', + } + }, + # 4 Find all home projects + {'$match': {'project.category': 'home'}}, + {'$count': 'tot'} + ] + c = current_app.db()['nodes'] + # Return either a list with one item or an empty list + r = list(c.aggregate(pipeline=pipeline)) + count = 0 if not r else r[0]['tot'] + return count diff --git a/cloud/stats/routes.py b/cloud/stats/routes.py index 8c51f75..416e00e 100644 --- a/cloud/stats/routes.py +++ b/cloud/stats/routes.py @@ -3,7 +3,7 @@ import datetime import functools from flask import Blueprint, jsonify -from cloud.stats import count_nodes, count_users +from cloud.stats import count_nodes, count_users, count_blender_sync blueprint = Blueprint('cloud.stats', __name__, url_prefix='/s') @@ -14,20 +14,17 @@ log = logging.getLogger(__name__) def get_stats(before: datetime.datetime): query_comments = {'node_type': 'comment'} query_assets = {'node_type': 'asset'} - # TODO Actually query per home project (and 1 blend per project) - query_user_blender_sync = {'name': 'startup.blend'} if before: d = {'_created': {'$lt': before}} query_comments.update(d) query_assets.update(d) - query_user_blender_sync.update(d) stats = { 'comments': count_nodes(query_comments), 'assets': count_nodes(query_assets), 'users_total': count_users(), - 'users_blender_sync': count_nodes(query_user_blender_sync), + 'users_blender_sync': count_blender_sync(), } return stats