MongoDB到BigQuery

MongoDB到BigQuery,mongodb,google-bigquery,Mongodb,Google Bigquery,将数据从mlab中托管的MongoDB导出到google bigquery的最佳方式是什么 最初,我尝试从MongoDB一次性加载到BigQuery,后来我考虑使用Pub/Sub实现到BigQuery的实时数据流 我需要第一次从mongodb加载到bigquery的帮助。通过对mongodb文档的基本阅读,您可以使用它将数据库转储为JSON。完成后,请参阅本主题,了解如何在将JSON文件复制到GCS后从JSON文件创建表。在我看来,最佳做法是构建自己的提取器。这可以用您选择的语言完成,您可以提取

将数据从mlab中托管的MongoDB导出到google bigquery的最佳方式是什么

最初,我尝试从MongoDB一次性加载到BigQuery,后来我考虑使用Pub/Sub实现到BigQuery的实时数据流


我需要第一次从mongodb加载到bigquery的帮助。

通过对mongodb文档的基本阅读,您可以使用它将数据库转储为JSON。完成后,请参阅本主题,了解如何在将JSON文件复制到GCS后从JSON文件创建表。

在我看来,最佳做法是构建自己的提取器。这可以用您选择的语言完成,您可以提取到CSV或JSON

但是,如果您希望使用一种快速方式,并且您的数据不是很大,可以放在一台服务器中,那么我建议使用
mongoexport
。假设您有一个简单的文档结构,如下所示:

{
    "_id" : "tdfMXH0En5of2rZXSQ2wpzVhZ",
    "statuses" : [ 
        {
            "status" : "dc9e5511-466c-4146-888a-574918cc2534",
            "score" : 53.24388894
        }
    ],
    "stored_at" : ISODate("2017-04-12T07:04:23.545Z")
}
然后需要定义BigQuery模式(
mongodb_Schema.json
),例如:

正如您在上面看到的,我将输出限制为100k条记录,因为我建议您在对所有数据执行此操作之前先运行sample并加载到BigQuery。运行上述命令后,您应该将示例数据保存在
sample.json
中,但有一个字段
$date
,这将导致您加载到BigQuery时出错。要解决此问题,我们可以使用
sed
将其替换为简单字段名:

# Fix Date field to make it compatible with BQ
sed -i 's/"\$date"/"date"/g' sample.json
现在,您可以使用以下命令压缩、上载到Google云存储(GCS),然后加载到BigQuery:

# Compress for faster load
gzip sample.json

# Move to GCloud
gsutil mv ./sample.json.gz gs://your-bucket/sample/sample.json.gz

# Load to BQ
bq load \
    --source_format=NEWLINE_DELIMITED_JSON \
    --max_bad_records=999999 \
    --ignore_unknown_values=true \
    --encoding=UTF-8 \
    --replace \
    "YOUR_DATASET.mongodb_sample" \
    "gs://your-bucket/sample/*.json.gz" \
    "mongodb_schema.json"
如果一切正常,则返回并从
mongoexport
命令中删除
--limit 100000
,然后再次运行上述命令以加载所有内容,而不是100k样本

替代解决方案:

如果您想要更大的灵活性,而性能不是您所关心的,那么您也可以使用
mongo
CLI工具。通过这种方式,您可以在JavaScript中编写提取逻辑,并对数据执行它,然后将输出发送到BigQuery。以下是我对相同流程所做的操作,但使用JavaScript以CSV格式输出,因此我可以更轻松地加载BigQuery:

# Export Logic in JavaScript
cat > export-csv.js <<EOF
var size = 100000;
var maxCount = 1;
for (x = 0; x < maxCount; x = x + 1) {
    var recToSkip = x * size;
    db.entities.find().skip(recToSkip).limit(size).forEach(function(record) {
        var row = record._id + "," + record.stored_at.toISOString();;
        record.statuses.forEach(function (l) {
            print(row + "," + l.status + "," + l.score)
        });
    });
}
EOF

# Execute on Mongo CLI
_MONGO_HOSTS="db-01:27017,db-02:27017,db-03:27017/sample?replicaSet=statuses"
mongo --quiet \
    "${_MONGO_HOSTS}" \
    export-csv.js \
    | split -l 500000 --filter='gzip > $FILE.csv.gz' - sample_

# Load all Splitted Files to Google Cloud Storage
gsutil -m mv ./sample_* gs://your-bucket/sample/

# Load files to BigQuery
bq load \
    --source_format=CSV \
    --max_bad_records=999999 \
    --ignore_unknown_values=true \
    --encoding=UTF-8 \
    --replace \
    "YOUR_DATASET.mongodb_sample" \
    "gs://your-bucket/sample/sample_*.csv.gz" \
    "ID,StoredDate:DATETIME,Status,Score:FLOAT"
#在JavaScript中导出逻辑

cat>export-csv.js您可以从MongoDB和中读取数据。您可以在NodeJS中找到一个示例

这是链接示例的扩展,可防止重复记录(只要它们仍然是流式缓冲区):


日期字段呢?当我将数据导出到日期/时间时,字段显示为“$date”,这对于BigQuery字段名是不可接受的。有什么解决方法吗?我想你需要先以某种方式重命名它们,很不幸。谢谢你,Elliott,我找到了一种方法来修复它,并将它作为这个问题的另一个答案提交,这可能会在将来帮助像我这样的人:-)谢谢你的解决方案。太棒了。但这种方法存在一个问题。在这里,BigQuery的模式已被明确修复。但从逻辑上讲,MongoDB的模式永远不会固定。所以我们不能依赖固定的模式文件进行bigquery。其次,新列或嵌套列很有可能出现在mongoDB中较新/最新的数据中。然后,一种方法是每次在MongoDB中存储一个全新的密钥时重复更改bigquery模式文件的模式,但是您将如何处理bigquery中已上载的数据。我很想听听你的想法。我完全理解你的观点,这也是我开始回答的主要原因,我建议你建立一个自定义提取器。BigQuery可以支持嵌套字段,因此这不是问题。为了在BigQuery中设计灵活的模式,我建议用两部分构建模式。公共字段将是固定的,大部分不会更改,以及一个数组类型的“元”字段。通过这种方式,您可以以键/值对的形式推送任何自定义值,并将它们全部以数组形式存储在“meta”字段中。我经常使用这种技术,它可能是您的一个很好的替代选项。这段代码将在哪里运行?在mongodb服务器上?您必须在自己的服务器或计算机上运行它。
# Compress for faster load
gzip sample.json

# Move to GCloud
gsutil mv ./sample.json.gz gs://your-bucket/sample/sample.json.gz

# Load to BQ
bq load \
    --source_format=NEWLINE_DELIMITED_JSON \
    --max_bad_records=999999 \
    --ignore_unknown_values=true \
    --encoding=UTF-8 \
    --replace \
    "YOUR_DATASET.mongodb_sample" \
    "gs://your-bucket/sample/*.json.gz" \
    "mongodb_schema.json"
# Export Logic in JavaScript
cat > export-csv.js <<EOF
var size = 100000;
var maxCount = 1;
for (x = 0; x < maxCount; x = x + 1) {
    var recToSkip = x * size;
    db.entities.find().skip(recToSkip).limit(size).forEach(function(record) {
        var row = record._id + "," + record.stored_at.toISOString();;
        record.statuses.forEach(function (l) {
            print(row + "," + l.status + "," + l.score)
        });
    });
}
EOF

# Execute on Mongo CLI
_MONGO_HOSTS="db-01:27017,db-02:27017,db-03:27017/sample?replicaSet=statuses"
mongo --quiet \
    "${_MONGO_HOSTS}" \
    export-csv.js \
    | split -l 500000 --filter='gzip > $FILE.csv.gz' - sample_

# Load all Splitted Files to Google Cloud Storage
gsutil -m mv ./sample_* gs://your-bucket/sample/

# Load files to BigQuery
bq load \
    --source_format=CSV \
    --max_bad_records=999999 \
    --ignore_unknown_values=true \
    --encoding=UTF-8 \
    --replace \
    "YOUR_DATASET.mongodb_sample" \
    "gs://your-bucket/sample/sample_*.csv.gz" \
    "ID,StoredDate:DATETIME,Status,Score:FLOAT"
    const { BigQuery } = require('@google-cloud/bigquery');
    const bigqueryClient = new BigQuery();

    ...

    const jsonData = // Array of documents from MongoDB

    const inputRows = jsonData.map(row => ({
      insertId: row._id,
      json: row
    }));
    const insertOptions = {
      raw: true
    };

    await bigqueryClient
      .dataset(datasetId)
      .table(tableId)
      .insert(inputRows, insertOptions);