JMJ
JMJ

Reputation: 571

Read first row in loop using sqlite's fetchone()

I am using a loop to get the contents of fetchone(), every time code reads fetchone() the cursor moves to the next row. I understand that I need to be careful. I am using the example found here https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-fetchone.html this works when I have more then one row but when there is a single row I get an error

    for k, v in cur.fetchone().items():
AttributeError: 'NoneType' object has no attribute 'items'

The two relevant functions

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

def open_sql(sql_folder, sql_name, sql_table):
    # databases are located at /work/jmjohnso1/db_project  
    path_name = os.path.join(sql_folder,sql_name).strip()
    con = lite.connect(path_name)
    con.row_factory = dict_factory
    cur = con.cursor()
    cur.execute('SELECT * FROM ' + sql_table) 

    dict_contents = defaultdict(list) 

    for row in cur:
        for k, v in cur.fetchone().items():
            dict_contents[k].append(v)

    con.close()
    print(dict_contents)
    return dict_contents

In case you want the entire code:

# python3.5
# pymongo version 3.2.2
# MongoDB shell version: 3.0.11

import os
import pymongo
from pymongo import MongoClient
import sqlite3 as lite
import pyewf
import hashlib
from itertools import chain
from collections import defaultdict
import pprint

def list_sql_db(folder):
    # need a list for multiprocessing so I made a file. 
    file_name = os.path.join(folder, 'sql_db')
    if not os.path.isfile(file_name):
        with open (file_name, 'w') as line:
            for (dirpath, dirs, files) in os.walk(folder):
                for name in files:
                    line.write(name + '\n')
    return file_name    

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

def open_sql(sql_folder, sql_name, sql_table):
    # databases are located at /work/jmjohnso1/db_project  
    path_name = os.path.join(sql_folder,sql_name).strip()
    con = lite.connect(path_name)
    con.row_factory = dict_factory
    cur = con.cursor()
    cur.execute('SELECT * FROM ' + sql_table) 

    dict_contents = defaultdict(list) 

    for row in cur:
        for k, v in cur.fetchone().items():
            dict_contents[k].append(v)

    con.close()
    print(dict_contents)
    return dict_contents

def insert_tsk_mongo(sql_folder, sql_name, sql_table):
    client = MongoClient() # connect to mongodb
    db = client.nus # make or use a db called nus
    contents = open_sql(sql_folder, sql_name, sql_table)
    collection = sql_name.strip().replace('-','_') # because mongo will write but not read a collection with -

    # document_id = db[collection].insert({ # sql_name is the hard drive name 
        # sql_table:
            # contents           
    # })

###############################################################################

sql_folder = '/work/jmjohnso1/db_project'    
# sql_tables = ['tsk_fs_info', 'tsk_image_info',
              # 'tsk_db_info ', 'tsk_image_names',
              # 'tsk_file_layout', 'tsk_objects',
              # 'tsk_files', 'tsk_vs_info', 'tsk_vs_parts']

sql_tables = ['tsk_fs_info']              

sql_folder_name = list_sql_db(sql_folder)

with open (sql_folder_name, 'r') as read: 
    sql_names = read.readlines()

for sql_name in sql_names:
    for sql_table in sql_tables:
        insert_tsk_mongo(sql_folder, sql_name, sql_table)
    break    

Upvotes: 1

Views: 2470

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1123840

You are fetching rows twice, once with the for row in cur: loop, then in the loop with cur.fetchone(). At the last row, you have run out of rows to fetch, so None is returned.

There is no need to use cur.fetchone() when you are already looping over the cursor. Just drop the cur.fetchone() call and use the row you already fetched with for:

for row in cur:
    for k, v in row.items():
        dict_contents[k].append(v)

Upvotes: 4

Related Questions