跳转到主要内容

一个命令行工具(和Python库)用于从CommCare HQ提取数据到SQL数据库或Excel工作簿

项目描述

CommCare Export

https://github.com/dimagi/commcare-export

Build Status Test coverage PyPI version

一个命令行工具(和Python库)用于从CommCare HQ REST API生成定制导出。

安装和快速开始

以下命令应在终端或命令行上运行。

在终端窗口或命令行中,为了简单起见,从主目录运行命令。

Python

检查已安装的Python版本。

此工具已在3.8到3.12版本的Python上进行了测试。

$ python3 --version

如果已安装Python,将显示其版本。

如果未安装Python,请下载并安装3.8到3.12版本的Python。

Virtualenv(可选)

建议为CommCare Export设置虚拟环境,以避免与其他Python应用程序发生冲突。

有关virtualenv的更多信息,请参阅https://docs.pythonlang.cn/3/tutorial/venv.html

使用以下命令设置虚拟环境:

$ python3 -m venv venv

通过运行以下命令激活虚拟环境:

$ source venv/bin/activate

注意:每次启动新的终端会话或命令行提示符时,都需要激活virtualenv。

为了方便,为了避免这样做,您可以在"venv"目录中创建一个别名来激活虚拟环境,只需将以下内容添加到您的.bashrc.zshrc文件中

$ alias venv='if [[ -d venv ]] ; then source venv/bin/activate ; fi'

然后您可以通过简单地输入以下内容来激活虚拟环境

$ venv

安装CommCare Export

通过pip安装CommCare Export

$ pip install commcare-export

CommCare HQ

  1. 如果您尚未注册,请注册CommCare HQ

  2. 创建一个项目空间和应用程序。

  3. 访问发布管理器,创建构建,点击星星以发布。

  4. 使用Web应用程序并填写一些表单。

  5. 修改examples/目录中的一个示例查询,将“过滤器值”列修改为与您的表单XMLNS/案例类型匹配。请参阅此页面以确定表单的XMLNS。

现在您可以运行以下示例

$ commcare-export \
     --query examples/demo-registration.xlsx \
     --project YOUR_PROJECT \
     --output-format markdown

$ commcare-export \
     --query examples/demo-registration.json \
     --project YOUR_PROJECT \
     --output-format markdown

$ commcare-export \
     --query examples/demo-deliveries.xlsx \
     --project YOUR_PROJECT \
     --output-format markdown

$ commcare-export \
     --query examples/demo-deliveries.json \
     --project YOUR_PROJECT \
     --output-format markdown

您将看到打印的表。将更改到--output-format sql --output URL_TO_YOUR_DB --since DATE以同步自该日期以来提交的所有表单。

示例查询文件以Excel和JSON格式提供。建议使用Excel格式,因为JSON格式可能会在未来库版本中更改。

命令行使用

命令行工具的基本用法是与保存的Excel或JSON查询一起使用(下面将说明如何编写这些内容)

$ commcare-export --commcare-hq <URL or alias like "local" or "prod"> \
                  --username <username> \
                  --project <project> \
                  --api-version <api version, defaults to latest known> \
                  --version <print current version> \
                  --query <excel file, json file, or raw json> \
                  --output-format <csv, xls, xlsx, json, markdown, sql> \
                  --output <file name or SQL database URL> \
                  --users <export data about project's mobile workers> \
                  --locations <export data about project's location hierarchy> \
                  --with-organization <export users, locations and joinable form or case tables>

有关完整选项列表,请参阅commcare-export --help

examples/目录中提供了CommCare演示应用程序的示例查询文件(可在CommCare HQ Exchange中找到)。

--output

CommCare Export使用SQLAlchemy的create_engine来建立数据库连接。这是基于RFC-1738协议的。一些常见示例

# Postgres
postgresql+psycopg2://scott:tiger@localhost/mydatabase

# MySQL
mysql+pymysql://scott:tiger@localhost/mydatabase

# MSSQL
mssql+pyodbc://scott:tiger@localhost/mydatabases?driver=ODBC+Driver+17+for+SQL+Server

Excel查询

Excel查询是任何.xlsx工作簿。工作簿中的每个工作表代表您希望创建的一个表。有两个分组列可以配置表格

  • 数据源:将其设置为form以导出表单数据,或case以导出案例数据。
  • 过滤器名称 / 过滤器值:这些列配对以过滤输入案例或表单。
  • 字段:您的SQL数据库中的目标。
  • 源字段:您希望从中提取的特定字段。这可以是任何JSON路径。

JSON查询

下面的表格中描述了JSON查询。您构建一个表示您所想查询的JSON对象。一种良好的入门方法是使用示例,或者您也可以创建一个Excel查询,并使用--dump-query运行工具以查看生成的JSON查询。

用户和位置数据

使用--users和--locations选项可以导出CommCare项目中的数据,这些数据可以与表单和案例数据一起使用。使用--with-organization选项执行所有这些操作,并在Excel查询规范中添加一个字段以进行连接。

指定--users选项或--with-organization选项将导出一个名为'commcare_users'的额外表,包含以下列

类型 说明
id 文本 主键
default_phone_number 文本
电子邮件 文本
first_name 文本
groups 文本
last_name 文本
phone_numbers 文本
resource_uri 文本
commcare_location_id 文本 外键到commcare_locations
commcare_location_ids 文本
commcare_primary_case_sharing_id 文本
commcare_project 文本
用户名 文本

'commare_users'表中的数据来自列表移动工作者API端点

指定 --locations 选项或 --with-organization 选项将导出一个名为 'commcare_locations' 的额外表格,包含以下列

类型 说明
id 文本
created_at 日期
文本
外部ID 文本
last_modified 日期
纬度 文本
位置数据 文本
位置ID 文本 主键
位置类型 文本
经度 文本
名称 文本
父级 文本 父级位置的资源URI
resource_uri 文本
站点代码 文本
行政位置类型 文本
位置类型代码 文本
位置类型名称 文本
位置类型父级 文本
位置级别代码 文本 列名取决于项目的组织
位置级别代码 文本 列名取决于项目的组织

'commcare_locations' 表中的数据来自位置API端点,以及来自位置类型API端点的某些附加列。如果为项目设置了组织级别,则表中最后几列存在。为每个组织级别创建一个列。列名来自您指定的位置类型。列值是您组织中该级别的包含位置的位置ID。考虑来自 CommCare帮助页面 的示例组织。'commcare_locations' 表的一个片段可能如下所示

位置ID 位置类型名称 chw 主管 诊所 地区
939fa8 地区 NULL NULL NULL 939fa8
c4cbef 诊所 NULL NULL c4cbef 939fa8
a9ca40 主管 NULL a9ca40 c4cbef 939fa8
4545b9 CHW 4545b9 a9ca40 c4cbef 939fa8

为了将表单或案例数据与 'commcare_users' 和 'commcare_locations' 连接起来,导出的表单和案例需要包含一个字段,用于标识提交它们的用户。--with-organization 选项会自动为 Excel 规范中的每个查询添加一个名为 'commcare_userid' 的字段,以便进行此操作。使用该字段,您可以使用带有连接的 SQL 查询来报告有关您组织中任何级别的数据。例如,要统计每个诊所所有工作人员提交的表单数量

SELECT l.clinic,
       COUNT(*)
FROM form_table t
LEFT JOIN (commcare_users u
           LEFT JOIN commcare_locations l
           ON u.commcare_location_id = l.location_id)
ON t.commcare_userid = u.id
GROUP BY l.clinic;

请注意,'commcare_users' 和 'commcare_locations' 表名被视为保留名称,并且如果给出将数据写入其中任何一个的查询规范,导出工具将产生错误。

导出工具会将所有用户写入 'commcare_users',并将所有位置写入 'commcare_locations',用当前数据覆盖现有行,并为新用户和位置添加行。如果您想从表中删除过时的用户或位置,请删除它们,下一次导出将仅保留当前的。如果您修改组织以添加或删除级别,您将更改 'commcare_locations' 表的列,并且您很可能在用新组织导出之前删除该表。

安排 DET 计划任务

安排 DET 在常规时间间隔内运行是保持您的数据库与 CommCare HQ 保持同步的有用策略。

安排 DET 运行的一种常见方法是在操作系统的调度库中调用脚本以执行 commcare-export 命令。可以在 examples/ 目录中找到 Windows 和 Linux 的示例脚本。

Windows

在 Windows 系统上,您可以使用 任务计划程序 运行计划脚本。

examples/ 目录包含一个示例脚本文件 scheduled_run_windows.bat,任务计划程序可以使用它来调用 commcare-export 命令。

要设置计划任务,您可以按照以下步骤操作。

  1. 将文件 scheduled_run_windows.bat 复制到系统上的任何所需位置(例如 文档
  2. 编辑复制的 .bat 文件并填写您自己的详细信息
  3. 按照 此处 提供的步骤进行操作,当提示输入 程序/脚本 时使用 .bat 文件。

Linux

在 Linux 系统上,您可以使用 crontab 命令在系统中创建计划操作(cron作业)。

《examples/》目录包含一个示例脚本文件,scheduled_run_linux.sh,可以被cron作业使用。要设置cron作业,请按照以下步骤进行。

  1. 将示例文件复制到主目录

cp ./examples/scheduled_run_linux.sh ~/scheduled_run_linux.sh

  1. 编辑文件以填充您的详细信息

nano ~/scheduled_run_linux.sh

  1. 通过追加到crontab文件来创建cron作业

crontab -e

在任意现有cron作业下添加条目。以下示例在每天的每12个小时顶部执行脚本文件

0 12 * * * bash ~/scheduled_run_linux.sh

您可以使用crontab.guru工具,这是一个非常有用的工具,可以生成和解释任何自定义cron计划。

Python库使用

作为库,各种commcare_export模块使得

  • 与CommCare HQ REST API交互变得容易
  • 对API执行"Minilinq"查询(一种非常简单的查询语言,如下所述)
  • 加载和保存Minilinq查询的JSON表示
  • 将Excel配置编译为Minilinq查询

直接访问CommCare HQ REST API

from commcare_export.checkpoint import CheckpointManagerWithDetails
from commcare_export.commcare_hq_client import CommCareHqClient, AUTH_MODE_APIKEY
from commcare_export.commcare_minilinq import get_paginator, PaginationMode

username = 'some@username.com'
domain = 'your-awesome-domain'
hq_host = 'https://commcarehq.org'
API_KEY= 'your_secret_api_key'

api_client = CommCareHqClient(hq_host, domain, username, API_KEY, AUTH_MODE_APIKEY)
case_paginator=get_paginator(resource='case', pagination_mode=PaginationMode.date_modified)
case_paginator.init()
checkpoint_manager=CheckpointManagerWithDetails(None, None, PaginationMode.date_modified)

cases = api_client.iterate('case', case_paginator, checkpoint_manager=checkpoint_manager)

for case in cases:
	print(case['case_id'])

对其执行minilinq查询,然后以JSON序列化的形式打印该查询

import json
import sys
from commcare_export.minilinq import *
from commcare_export.commcare_hq_client import CommCareHqClient
from commcare_export.commcare_minilinq import CommCareHqEnv
from commcare_export.env import BuiltInEnv, JsonPathEnv
from commcare_export.writers import StreamingMarkdownTableWriter

api_client = CommCareHqClient(
    url="http://www.commcarehq.org",
    project='your_project',
    username='your_username',
    password='password',
    version='0.5'
)

source = Map(
   source=Apply(
       Reference("api_data"),
       Literal("form"),
       Literal({"filter": {"term": {"app_id": "whatever"}}})
   ),
   body=List([
       Reference("received_on"),
       Reference("form.gender"),
   ])
)

query = Emit(
   'demo-table',
   [
       Literal('Received On'),
       Literal('Gender')
   ],
   source
)

print(json.dumps(query.to_jvalue(), indent=2))

results = query.eval(BuiltInEnv() | CommCareHqEnv(api_client) | JsonPathEnv())

if len(list(env.emitted_tables())) > 0:
    with StreamingMarkdownTableWriter(sys.stdout) as writer:
        for table in env.emitted_tables():
            writer.write_table(table)

这将输出与以下等效的JSON

{
    "Emit": {
        "headings": [
            {
                "Lit": "Received On"
            },
            {
                "Lit": "Gender"
            }
        ],
        "source": {
            "Map": {
                "body": {
                    "List": [
                        {
                            "Ref": "received_on"
                        },
                        {
                            "Ref": "form.gender"
                        }
                    ]
                },
                "name": null,
                "source": {
                    "Apply": {
                        "args": [
                            {
                                "Lit": "form"
                            },
                            {
                                "Lit": {
                                    "filter": {
                                        "term": {
                                            "app_id": "whatever"
                                        }
                                    }
                                }
                            }
                        ],
                        "fn": {
                            "Ref": "api_data"
                        }
                    }
                }
            }
        },
        "table": "demo-table"
    }
}

MiniLinq参考

抽象语法可以直接在commcare_export.minilinq模块中检查。请注意,函数和原语之间的选择是为了故意展示MiniLinq的结构,以便进行可能的优化,并限制整体语言。

以下是关于抽象语法和语义的描述

Python JSON 它评估为
Literal(v) {"Lit": v} v
Reference(x) {"Ref": x} 在环境中解析为x的任何内容
List([a, b, c, ...]) {"List": [a, b, c, ...} abc评估得到的内容列表
Map(source, name, body) {"Map": {"source": ..., "name": ..., "body": ...} source中的每个元素评估body。如果提供了name,则将元素绑定到它,否则它将替换整个环境。
FlatMap(source, name, body) {"FlatMap": {"source" ... etc}} 映射后扁平化,类似于嵌套列表推导式
Filter(source, name, body) 等等
Bind(value, name, body) 等等 当评估body时,将value的结果绑定到name
Emit(table, headings, rows) 等等 发出带有headingsrowstable。注意,table是一个字符串,headings是一个表达式列表,而rows是一个表达式列表的列表。请参见下面的输出说明。
Apply(fn, args) 等等 fn评估为函数,并将所有args应用于该函数。

通过环境提供内置函数,如api_data和基本算术和比较,通过使用Ref以名称引用,并通过Apply使用。

内置函数列表

函数 描述 示例使用
+, -, *, //, /, >, <, >=, <= 标准数学
len 长度
bool 布尔值
str2bool 将字符串转换为布尔值。真值是'true','t','1'(不区分大小写)
str2date 将字符串转换为日期
bool2int 将布尔值转换为整数(0,1)
str2num 将字符串解析为数字
format-uuid 解析十六进制UUID,并格式化为带连字符的组
substr 返回通过[第一个参数,第二个参数)索引的子串,零索引。 substr(2, 5) of 'abcdef' = 'cde'
selected-at 返回字符串中的第N个单词。N是零索引。 selected-at(3) - 返回第4个单词
selected 如果给定的单词在值中,则返回 True。 selected(发热)
count-selected 计算单词数量
json2str 将 JSON 对象转换为字符串
template 渲染字符串模板(不稳健) template({}, on {}, state, date)
attachment_url 将附件名称转换为下载 URL
form_url 输出 CommCare HQ 上表单视图的 URL
case_url 输出 CommCare HQ 上案例视图的 URL
unique 输出列表中的唯一值

输出格式

您的 MiniLinq 可以通过使用 Emit 表达式定义多个包含标题的表格,以及它们的内容行,或者简单地返回单个查询的结果。

如果您的 MiniLinq 不包含任何 Emit 表达式,那么表达式的结果将以格式化的 JSON 打印到标准输出。

如果您的 MiniLinq 确实 包含 Emit 表达式,则有许多格式可用,通过 --output-format <format> 选项选择,并且可以使用 --output <file> 命令行选项将其输出到文件。

  • csv:每个表格都将是一个 Zip 存档内的 CSV 文件。
  • xls:每个表格都将是一个旧格式 Excel 电子表格中的工作表。
  • xlsx:每个表格都将是一个新格式 Excel 电子表格中的工作表。
  • json:每个表格都将是一个 JSON 字典的成员,打印到标准输出。
  • markdown:表格将以 Markdown 格式流到标准输出(非常适合调试查询)。
  • sql:所有数据都将被“插入或更新”到您指定的 SQL 数据库中,包括创建所需的表和列。

依赖项

所需的依赖项将通过 pip 自动安装。但由于您可能不关心所有导出格式,因此这些依赖项是可选的。以下是安装方法:

# To export "xlsx"
$ pip install "commcare-export[xlsx]"

# To export "xls"
$ pip install "commcare-export[xls]"

# To sync with a Postgres database
$ pip install "commcare-export[postgres]"

# To sync with a mysql database
$ pip install "commcare-export[mysql]"

# To sync with a database which uses odbc (e.g. mssql)
$ pip install "commcare-export[odbc]"

# To sync with another SQL database supported by SQLAlchemy
$ pip install "commcare-export[base_sql]"
# Then install the Python package for your database

贡献

0. 如果您尚未注册,请前往 https://github.com 注册 GitHub。

1. 在 https://github.com/dimagi/commcare-export 上叉取存储库。

2. 克隆您的叉取,安装到虚拟环境,并开始一个功能分支

$ git clone git@github.com:dimagi/commcare-export.git
$ cd commcare-export
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -e ".[test]"
$ git checkout -b my-super-duper-feature

3. 进行编辑。

4. 确保测试通过。测试所有版本的最佳方法是注册 https://travis-ci.org 并为您的叉取打开自动持续测试。

$ py.test
=============== test session starts ===============
platform darwin -- Python 2.7.3 -- pytest-2.3.4
collected 17 items

tests/test_commcare_minilinq.py .
tests/test_excel_query.py ....
tests/test_minilinq.py ........
tests/test_repeatable_iterator.py .
tests/test_writers.py ...

============ 17 passed in 2.09 seconds ============

5. 在 envminilinq 模块中使用类型提示。请确保这些模块中的任何更改都遵循这些类型。

$ mypy --install-types @mypy_typed_modules.txt

6. 将功能分支推上去

$ git push -u origin my-super-duper-feature

7. 访问 https://github.com/dimagi/commcare-export 并提交一个拉取请求。

接受我们对您的贡献的感激之情:谢谢!

发布流程

1. 为发布创建标签

$ git tag -a "X.YY.0" -m "Release X.YY.0"
$ git push --tags

2. 创建源分发

$ python setup.py sdist

确保存档(dist/commcare-export-X.YY.0.tar.gz)具有正确的版本号(与标签名称匹配)。

3. 上传到 pypi

$ pip install twine
$ twine upload -u dimagi dist/commcare-export-X.YY.0.tar.gz

验证上传

https://pypi.python.org/pypi/commcare-export

5. 在 github 上创建发布

https://github.com/dimagi/commcare-export/releases

一旦发布发布,就会启动一个 GitHub 工作流,该工作流编译与 Linux 和 Windows 机器兼容的 DET 可执行文件,并将其作为资产添加到发布中。

【对于基于 Linux 的用户】如果您决定下载和使用可执行文件,请确保文件具有可执行权限,然后可以通过命令行像任何其他可执行文件一样调用它。

测试和测试数据库

以下命令将运行整个测试套件(需要设置如下 DB 环境变量)

$ py.test

要运行单个测试类或方法,您可以运行,例如

$ py.test -k "TestExcelQuery"
$ py.test -k "test_get_queries_from_excel"

要排除数据库测试,您可以运行

$ py.test -m "not dbtest"

在运行数据库测试时,支持 PostgreSQL、MySQL、MSSQL。

要对选定的数据库运行测试,可以使用以下标记:

$ py.test -m [postgres,mysql,mssql]

数据库URL可以通过环境变量进行覆盖。

POSTGRES_URL=postgresql://user:password@host/
MYSQL_URL=mysql+pymysql://user:password@host/
MSSQL_URL=mssql+pyodbc://user:password@host/

Postgresql

$ docker pull postgres:9.6
$ docker run --name ccexport-postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres:9.6
$ export POSTGRES_URL=postgresql://postgres:postgres@localhost/

Docker postgres镜像文档

MySQL

$ docker pull mysql
$ docker run --name ccexport-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pw -e MYSQL_USER=travis -e MYSQL_PASSWORD='' -d mysql

# create travis user
$ docker run -it --link ccexport-mysql:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'
mysql> CREATE USER 'travis'@'%';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'travis'@'%';

MSSQL

$ docker pull mcr.microsoft.com/mssql/server:2017-latest 
$ docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Password@123" -p 1433:1433 --name mssql1 -d microsoft/mssql-server-linux:2017-latest

# install driver
$ curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
$ echo "deb [arch=amd64] https://packages.microsoft.com/ubuntu/$(lsb_release -rs)/prod $(lsb_release -rs) main" | sudo tee /etc/apt/sources.list.d/mssql-release.list

$ sudo apt-get update
$ sudo ACCEPT_EULA=Y apt-get install msodbcsql17
$ odbcinst -q -d

适用于Mac OS的MSSQL

$ docker pull mcr.microsoft.com/mssql/server:2017-latest 
$ docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Password@123" -p 1433:1433 --name mssql1 -d microsoft/mssql-server-linux:2017-latest

# Install driver
$ brew install unixodbc freetds

# Add the following 5 lines to /usr/local/etc/odbcinst.ini
[ODBC Driver 17 for SQL Server]
Description=FreeTDS Driver for Linux & MSSQL
Driver=/usr/local/lib/libtdsodbc.so
Setup=/usr/local/lib/libtdsodbc.so
UsageCount=1

# Create a soft link from /etc/odbcinst.ini to actual file
$ sudo ln -s /usr/local/etc/odbcinst.ini /etc/odbcinst.ini

集成测试

运行集成测试需要来自CommCare HQ的API凭证,该凭证可以访问corpora域。此用户应仅具有访问corpora域的权限。

需要按以下方式设置环境变量:

$ export HQ_USERNAME=<username>
$ export HQ_API_KEY=<apikey>

对于Travis构建,这些作为加密变量包含在travis配置中。

项目详情


发布历史 发布通知 | RSS订阅

下载文件

下载适合您平台文件的文件。如果您不确定要选择哪一个,请了解更多关于安装包的信息。

源分布

commcare-export-1.13.0.tar.gz (150.5 kB 查看哈希)

上传时间

由以下组织支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面