Python MongoDB查询将段数据请求分块

时间:2016-06-17 18:07:38

标签: python mongodb rest servicenow chunked

我正在编写一个python脚本,它执行以下步骤。

查询MongoDB数据库 解析并汇总结果 通过REST API将数据上载到ServiceNow表

但是,脚本工作正常,数据集太大,60秒后REST事务超时(连接由目标上的ServiceNow服务器关闭)。

我需要将数据分段为块并为每个数据块发送单独的REST事务,以确保通过POST发送完整数据集而不会达到超时限制。

如何通过修改下面的脚本来实现这一目标?

#!/usr/bin/env python

from config import *

import os, sys

mypath = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(mypath, "api-python-client"))

from apiclient.mongo import *

from pymongo import MongoClient

import json

import requests

from bson.json_util import dumps

client = MongoClient(mongo_uri)

#Create ServiceNow URL
svcnow_url = create_svcnow_url('u_imp_cmps')

#BITSDB Nmap Collection
db = client[mongo_db]

#Aggregate - RDBMS equivalent to Alias select x as y
#Rename fields to match ServiceNow field names
computers = db['computer'].aggregate([
        {"$unwind": "$hostnames"},
        {"$project" : {
                "_id":0,
                "u_hostname": "$hostnames.name",
                "u_ipv4": "$addresses.ipv4",
                "u_status": "$status.state",
                "u_updated_timestamp": "$last_seen"
        }}

])

j = dumps({"records":computers})
#print(j)


#Set proper headers
headers = {"Content-Type":"application/json","Accept":"application/json"}

#Build HTTP Request
response = requests.post(url=svcnow_url, auth=(svcnow_user, svcnow_pwd), headers=headers ,data=j)

#Check for HTTP codes other than 200
if response.status_code != 200:
        print('Status:', response.status_code, 'Headers:', response.headers, 'Response Text', response.text, 'Error Response:',response.json())
        exit()

#Decode the JSON response into a dictionary and use the data
print('Status:',response.status_code,'Headers:',response.headers,'Response:',response.json())

更新:我有一个计划,但我不确定如何实现这一点。

  • 将光标设置为固定批量大小为1000条记录
  • 批处理已满时,创建JSON输出并通过请求
  • 发送数据
  • 循环:继续抓取新批次并将每批次发送到目的地,直到达到整个数据集

https://docs.mongodb.com/v3.0/reference/method/cursor.batchSize/

基本上我认为我可以通过创建批次并循环遍历批次来解决这个问题,每次都有一个新的API调用。如果这是一个好的计划以及如何实施解决方案,请告诉我是否有任何想法。感谢。

1 个答案:

答案 0 :(得分:1)

public class Setting extends AbstractSetting { private boolean extraProperty = false; public void getExtraProperty() { return extraProperty; } } public class Foobar extends AbstractFoo { public void foobar() { setting.getProperty(); setting.getExtraProperty(); // CAN'T RESOLVE ! } } Foo foo = new Foo(); foo.setSetting(new Setting()); foo.foobar(); 将返回一个列表,因此您可以通过调用j = dumps({"records":computers})或迭代for循环轻松指向单个数据条目。 ServiceNow应接受这些条目中的每一个。

j[x]

如果MongoDB中有100个新条目,这将对ServiceNow进行100次POST调用。您的ServiceNow实例应该能够处理负载,并且您可以非常轻松地识别无法加载的记录。

但是,如果您因任何原因需要缩小通话次数,我建议您将列表拆分为“子列表”,例如one-liner featured in this answer

# Set proper headers (these are always the same, so this
# can be assigned outside of the for loop)
headers = {"Content-Type":"application/json","Accept":"application/json"}

for data_point in j:

    #Build HTTP Request (Note we are using data_point instead of j)
    response = requests.post(url=svcnow_url, auth=(svcnow_user, svcnow_pwd), headers=headers ,data=data_point)

    #Check for HTTP codes other than 200
    if response.status_code != 200:
        print('Status:', response.status_code, 'Headers:', response.headers, 'Response Text', response.text, 'Error Response:',response.json())
    else:
        # This is a response of success for a single record
        print('Status:',response.status_code,'Headers:',response.headers,'Response:',response.json())

exit()