def loop_exclusion_key_and_ref(self, collection: str, key: str, exclusion: tuple) -> dict: """ 対象のコレクション内のドキュメントを全て、指定のキーの要素を抜き出してrefに変換してDBに入れる また、取り出したデータ内の指定の要素を除外することもできる :param str collection: 変換対象のコレクション :param str key: refに変換開始する対象のキー :param tuple exclusion: 除外するキーの設定 :return: result :rtype: dict """ docs = self.db[collection].find() if docs.count() == 0: sys.exit('対象のドキュメントは存在しません') id_list = [] for doc in docs: if self.get_structure(collection, doc['_id']) == 'emb': id_list.append(doc['_id']) if len(id_list) == 0: sys.exit('変換対象のドキュメントは全てreferenceです') result_list = [] for oid in id_list: emb_result = self.db[collection].find_one({'_id': oid}) del emb_result['_id'] convert = Convert() pull_result = convert.pullout_key(emb_result, key) if not pull_result: sys.exit(f'{key}は存在しません') if exclusion: result = convert.exclusion_key(pull_result, exclusion) if pull_result == result: sys.exit(f'{list(exclusion)}は存在しません') else: result = pull_result converted_edman = convert.dict_to_edman(result) structured_result = self.insert(converted_edman) structured_result.reverse() result_list.append(structured_result) result = {} if len(result_list): result.update({'result': result_list}) print('\r\n') # 改行できない問題を回避 return result
def update(self, collection: str, oid: Union[str, ObjectId], amend_data: dict, structure: str) -> bool: """ 修正データを用いてDBデータをアップデート :param str collection: :param oid: :type oid: str or ObjectId :param dict amend_data: :param str structure: :return: :rtype: bool """ oid = Utils.conv_objectid(oid) db_result = self.db[collection].find_one({'_id': oid}) if db_result is None: sys.exit('該当するドキュメントは存在しません') if structure == 'emb': try: # 日付データを日付オブジェクトに変換するため、 # 必ずコンバートしてからマージする convert = Convert() converted_amend_data = convert.emb(amend_data) amended = self._merge(db_result, converted_amend_data) except ValueError as e: sys.exit(e) elif structure == 'ref': # 日付データを日付オブジェクトに変換 converted_amend_data = self._convert_datetime_dict(amend_data) amended = {**db_result, **converted_amend_data} else: sys.exit('structureはrefまたはembの指定が必要です') try: replace_result = self.db[collection].replace_one({'_id': oid}, amended) except errors.OperationFailure: sys.exit('アップデートに失敗しました') return True if replace_result.modified_count == 1 else False
def setUp(self): self.convert = Convert() self.config = Config() self.parent = self.config.parent self.child = self.config.child self.date = self.config.date
class TestConvert(TestCase): def setUp(self): self.convert = Convert() self.config = Config() self.parent = self.config.parent self.child = self.config.child self.date = self.config.date def test__get_child_reference(self): # すでにparentが作られていた場合 # (この関数後の処理にDBRefオブジェクトが0個の時の処理が書かれているため0個でもOK) test_data = {self.parent: {'_id': ObjectId()}} actual = self.convert._get_child_reference(test_data) self.assertEqual(0, len(list(actual.values())[0])) # テスト辞書データの中身が辞書の場合 test_data = {'test_collection': {'_id': ObjectId()}} actual = self.convert._get_child_reference(test_data) self.assertIsInstance(actual, dict) self.assertEqual(self.config.child, list(actual.keys())[0]) self.assertEqual(1, len(list(actual.values())[0])) # テスト辞書データの中身がリストの場合 test_data = { 'test_collection': [ {'_id': ObjectId()}, {'_id': ObjectId()} ] } actual = self.convert._get_child_reference(test_data) self.assertEqual(2, len(list(actual.values())[0])) def test__convert_datetime(self): # データ構造のテスト test_data = {'start_date': {'#date': '1981-04-23'}} actual = self.convert._convert_datetime(test_data) self.assertIsInstance(actual, dict) self.assertIsInstance(list(actual.values())[0], datetime) def test__list_organize(self): # データ構造のテスト test_data = [ { 'honda': [ {'name': 'NSX', 'power': '280'} ] }, { 'honda': [ {'name': 'S800', 'first model year': '1966'} ] } ] actual = self.convert._list_organize(test_data) self.assertIsInstance(actual, list) self.assertEqual('honda', list(actual[0].keys())[0]) self.assertEqual(2, len(list(actual[0].values())[0])) for i in list(actual[0].values())[0]: with self.subTest(i=i): self.assertIsInstance(i, dict) def test__list_intercept_hook(self): data = { 'parent_data': 'data1', 'delete_coll': {'data': '1', 'data2': '2'}, 'child': [ DBRef('test_collection', ObjectId()), DBRef('test_collection', ObjectId())]} actual = self.convert._list_intercept_hook('test_coll', data) # 子要素のデータ(この場合はdata['delete_coll'])が削除されているか self.assertIsInstance(actual, dict) for k, v in actual.items(): with self.subTest(v=v): self.assertNotIn('delete_coll', v[0]) def test__attached_oid(self): # 辞書内辞書の場合 test_data = { 'collection': { 'car_name': 'NSX', 'Purchase year': '1993' } } actual = self.convert._attached_oid(test_data) self.assertIsInstance(actual, dict) self.assertTrue(True if '_id' in list(actual.values())[0] else False) self.assertIsInstance(list(actual.values())[0]['_id'], ObjectId) # 辞書内リストの場合 test_data = { 'collection': [ { 'car_name': 'NSX', 'Purchase year': '1993' } ] } actual = self.convert._attached_oid(test_data) self.assertTrue( True if '_id' in list(actual.values())[0][0] else False) self.assertIsInstance(list(actual.values())[0][0]['_id'], ObjectId) def test__field_name_check(self): illegals = [None, '', '$aa', '.aa'] for i in illegals: with self.subTest(i=i): actual = self.convert._field_name_check(i) self.assertFalse(actual) # 文字列以外の方は文字列に変換される actual = self.convert._field_name_check(455) self.assertTrue(actual) def test__date_replace(self): list_data = [{self.date: '2019-02-28'}, {self.date: '2019-03-01 13:56:28'}, 1, 'text'] expected = [datetime(2019, 2, 28), datetime(2019, 3, 1, 13, 56, 28), 1, 'text'] actual = self.convert._date_replace(list_data) self.assertListEqual(expected, actual) def test_pullout_key(self): data = { 'beamtime': { 'username': '******', 'expInfo': [ { 'date': '2019-08-02', 'position': {'a': '1', 'b': '2'}, 'file': {'name': 'sample.jpg'}, 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } }, { 'date': '2019-08-03', 'position': {'a': '11', 'b': '22'}, 'file': {'name': 'process.jpg'}, 'process': { 'cc': '44', 'file': { 'name': 'machine3.log', 'file': {'name': 'machine4.log'} } } }, ]} } key = 'expInfo' actual = self.convert.pullout_key(data, key) expected = { 'expInfo': [ { 'date': '2019-08-02', 'position': {'a': '1', 'b': '2'}, 'file': {'name': 'sample.jpg'}, 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } }, { 'date': '2019-08-03', 'position': {'a': '11', 'b': '22'}, 'file': {'name': 'process.jpg'}, 'process': { 'cc': '44', 'file': { 'name': 'machine3.log', 'file': {'name': 'machine4.log'} } } }, ]} self.assertIsInstance(actual, dict) self.assertDictEqual(expected, actual) # 別のデータ(この場合は1番目のprocessを拾ってくる) data2 = { 'beamtime': { 'username': '******', 'expInfo': [ { 'date': '2019-08-02', 'position': {'a': '1', 'b': '2'}, 'file': {'name': 'sample.jpg'}, 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } }, { 'date': '2019-08-03', 'position': {'a': '11', 'b': '22'}, 'file': {'name': 'process.jpg'}, 'process': { 'cc': '44', 'file': { 'name': 'machine3.log', 'file': {'name': 'machine4.log'} } } }, ]} } key = 'process' actual = self.convert.pullout_key(data2, key) expected = { 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } } self.assertDictEqual(expected, actual) # 指定のキーが見つからなかった時 key = 'foobar' actual = self.convert.pullout_key(data, key) self.assertDictEqual({}, actual) # データが無かった場合 data3 = {} key = 'expInfo' actual = self.convert.pullout_key(data3, key) self.assertDictEqual({}, actual) def test_exclusion_key(self): data = { 'expInfo': [ { 'date': '2019-08-02', 'position': {'a': '1', 'b': '2'}, 'file': {'name': 'sample.jpg'}, 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } }, { 'date': '2019-08-03', 'position': {'a': '11', 'b': '22'}, 'file': {'name': 'process.jpg'}, 'process': { 'cc': '44', 'file': { 'name': 'machine3.log', 'file': {'name': 'machine4.log'} } } }, ]} exclusion = ('position',) actual = self.convert.exclusion_key(data, exclusion) expected = { 'expInfo': [ { 'date': '2019-08-02', 'file': {'name': 'sample.jpg'}, 'process': { 'cc': '33', 'file': { 'name': 'machine.log', 'file': {'name': 'machine2.log'} } } }, { 'date': '2019-08-03', 'file': {'name': 'process.jpg'}, 'process': { 'cc': '44', 'file': { 'name': 'machine3.log', 'file': {'name': 'machine4.log'} } } }, ]} self.assertIsInstance(actual, dict) self.assertDictEqual(expected, actual) # 指定のキーが見つからなかった時 exclusion = ('foobar',) actual = self.convert.exclusion_key(data, exclusion) self.assertDictEqual(data, actual) def test__ref(self): pass # テスト用jsonの読み込み # with open('./test_json_files/ref_test_premo.json') as f: # jsondict = json.load(f) # # actual = self.convert._ref(jsondict) # # with open('./test_json_files/ref_test_premo_result.json', 'w') as f: # f.write(dumps(actual, ensure_ascii=False, indent=4)) # TODO あとでテストデータを追加し、assertできるようにする def test__emb(self): pass
def test_add_file_reference(self): if not self.db_server_connect: return # refの場合 # refデータ入力 ref_json = { "structure_1": [{ "position": "top", "username": "******", "structure_2": [{ "maker": "Ferrari", "carname": "F355", "power": 380, "float_val": 4453.456 }, { "maker": "HONDA", "carname": "NSX", "power": 280, "float_val": 321.56, "start_date": { "#date": "1981-04-23" }, "structure_3_1": [{ "filename": "test1.txt", "name": "添付ファイル1" }, { "filename": "test2.txt", "name": "添付ファイル2" }], "structure_3_2": [{ "filename": "test3.txt", "name": "添付ファイル3", "structure_4": { "filename": "test4.txt", "name": "添付ファイル4", "structure_5": [{ "url": "example2.com", "name": "テストURL2" }, { "url": "example3.com", "name": "テストURL3" }] }, "structure_6": [{ "url": "example_x.com", "name": "テストURL_x" }, { "url": "example_y.com", "name": "テストURL_y" }], "structure_5": { "url": "example.com", "name": "テストURL1", "structure_5": { "url": "example4.com", "name": "テストURL4" } } }] }] }] } convert = Convert() converted_edman = convert.dict_to_edman(ref_json, mode='ref') insert_result = self.db.insert(converted_edman) with tempfile.TemporaryDirectory() as tmp_dir: p = Path(tmp_dir) expected = [] for i in range(2): gen_file = 'insert_file_ref_test' + str(i) + '.txt' gen_path = p / gen_file with gen_path.open('w') as f: test_var = 'test' + str(i) expected.append((gen_file, test_var)) f.write(test_var) file_path = tuple(sorted(p.glob('insert_file_ref_test*.txt'))) # メソッド実行 collection = 'structure_5' oid = [i[collection][0] for i in insert_result if collection in i][0] insert_file_result = self.file.add_file_reference(collection, oid, file_path, 'ref', compress=True) # DBからデータ取得 query = {'_id': oid} result = self.testdb[collection].find_one(query) # 取得したデータからgridfsのファイルを取得 actual = [] self.fs = gridfs.GridFS(self.testdb) for file_oid in result[self.config.file]: data = self.fs.get(file_oid) d = data.read() if hasattr(data, 'compress') and data.compress == 'gzip': d = gzip.decompress(d) actual.append((data.filename, d.decode())) # テスト self.assertTrue(insert_file_result) self.assertListEqual(sorted(actual), sorted(expected)) # embの場合 data = { "position": "top", "structure_2": [{ "maker": "Ferrari", "carname": "F355", "power": 380, "float_val": 4453.456 }, { "maker": "HONDA", "carname": "NSX", "power": 280, "float_val": 321.56, "structure_3_1": [{ "filename": "test1.txt", "name": "添付ファイル1" }, { "filename": "test2.txt", "name": "添付ファイル2" }], "structure_3_2": [{ "filename": "test3.txt", "name": "添付ファイル3", "structure_4": { "filename": "test4.txt", "name": "添付ファイル4", "structure_5": [{ "url": "example2.com", "name": "テストURL2" }, { "url": "example3.com", "name": "テストURL3" }] }, "structure_6": [{ "url": "example_x.com", "name": "テストURL_x" }, { "url": "example_y.com", "name": "テストURL_y" }], "structure_5": { "url": "example.com", "name": "テストURL1", "structure_5": { "url": "example4.com", "name": "テストURL4" } } }] }] } insert_result = self.testdb['structure_emb'].insert_one(data) with tempfile.TemporaryDirectory() as tmp_dir: p = Path(tmp_dir) expected = [] for i in range(2): gen_file = 'emb_test' + str(i) + '.txt' gen_path = p / gen_file with gen_path.open('w') as f: test_var = 'test' + str(i) f.write(test_var) expected.append(test_var) files = tuple(sorted(p.glob('emb_test*.txt'))) collection = 'structure_emb' oid = insert_result.inserted_id query = ['structure_2', '1'] # メソッド実行 insert_file_emb_result = self.file.add_file_reference( collection, oid, files, 'emb', query, compress=True) # ドキュメントをfindして出す result = self.testdb[collection].find_one({'_id': oid}) # gridfsからデータ取得 out_data = [] self.fs = gridfs.GridFS(self.testdb) for oid in result['structure_2'][1][self.config.file]: data = self.fs.get(oid) f_data = data.read() if hasattr(data, 'compress') and data.compress == 'gzip': f_data = gzip.decompress(f_data) out_data.append(f_data.decode()) # DBデータとファイルのデータに差異はないか self.assertListEqual(sorted(expected), sorted(out_data)) # メソッド成功時のフラグ self.assertTrue(insert_file_emb_result)
def structure(self, collection: str, oid: ObjectId, structure_mode: str, new_collection: str) -> list: """ 構造をrefからembへ、またはembからrefへ変更する :param str collection: :param ObjectId oid: :param str structure_mode: :param str new_collection: :return: structured_result :rtype: list """ oid = Utils.conv_objectid(oid) # refデータをembに変換する if structure_mode == 'emb': # 自分データ取り出し ref_result = self.doc(collection, oid, query=None, reference_delete=False) reference_point_result = self.get_reference_point( ref_result) if reference_point_result[self.child]: # 子データを取り出し children = self.get_child_all({collection: ref_result}) # 自分のリファレンスデータとidを削除 for del_key in (self.parent, self.child, '_id'): if del_key in ref_result: del ref_result[del_key] # 子のリファレンスデータ削除 non_ref_children = self.delete_reference(children, ('_id', self.parent, self.child)) # 自分と子要素をマージする ref_result.update(non_ref_children) convert = Convert() converted_edman = convert.dict_to_edman( {new_collection: ref_result}, mode='emb') structured_result = self.insert(converted_edman) # 子が存在しないドキュメントの場合(新たなコレクションとして切り出す) else: # 自分のリファレンスデータとidを削除 for del_key in (self.parent, '_id'): if del_key in ref_result: del ref_result[del_key] convert = Convert() converted_edman = convert.dict_to_edman( {new_collection: ref_result}, mode='emb') structured_result = self.insert(converted_edman) # embからrefに変換 elif structure_mode == 'ref': emb_result = self.db[collection].find_one({'_id': oid}) del emb_result['_id'] convert = Convert() converted_edman = convert.dict_to_edman( {new_collection: emb_result}, mode='ref') structured_result = self.insert(converted_edman) structured_result.reverse() else: sys.exit('構造はrefかembを指定してください') return structured_result
parser.error("--structure requires 'ref' or 'emb'.") # 結果を記録する場合はパスの存在を調べる if args.result_dir is not None: p = Path(args.result_dir) if not p.exists() and not p.is_dir(): sys.exit('パスが不正です') # iniファイル読み込み settings = configparser.ConfigParser() settings.read(Path.cwd() / 'ini' / 'db.ini') con = dict([i for i in settings['DB'].items()]) db = DB(con) jm = JsonManager() convert = Convert() json_files = Action.files_read(args.path, 'json') for file in Action.file_gen(json_files): # Ednman用にjsonをコンバート converted_edman = convert.dict_to_edman(file, mode=args.structure) # コンバート結果を保存する場合 # jm.save({'converted_edman': converted_edman}, args.result_dir, # name='edman_json_list', date=True) # DBへインサート inserted_report = db.insert(converted_edman) if args.result_dir is not None: jm.save({'inserted_report': inserted_report}, args.result_dir,