2

I'm using Jsonlines aka ndjson, and want to edit a single key/value in a single line using python and update the line in the file.

Currently, the python libraries jsonlines and json-lines seem only to allow you to read existing entries or write new entries but not edit existing entries.

For example, in the jsonlines library, you can open the file and wrap the objects in reader or writer :

import jsonlines
with jsonlines.open('input.jsonl') as reader:
    for obj in reader:
        ...

with jsonlines.open('output.jsonl', mode='w') as writer:
    writer.write(...)

Say you have the following jsonlines file :

{"name":"Alice","age":24}
{"name":"Bob","age":22}

Updating a dictionary in python is fairly easy. In this case, it would be something like :

entry = {"name":"Alice","age":24}
entry.update({"age":25})

And the library seems to open the lines as dictionaries. And you can call the update method from within the jsonlines library :

import jsonlines
with open('names.jsonl', 'rb') as f:
    for item in json_lines.reader(f):
        item.update({'age':25})
        print(item['age'])

This has two problems :

  • it will not actually update the file ... just the dictionary temporarily
    • the file names.jsonl remains unchanged
  • it will do this for all the entries and not just a specific entry / line
    • this is of course because opened within a loop
    • you can go to a specific line via line number based on this solution
    • but it presumes you know the specific line number
    • when really you just want to find Alice by name and update her age in that entry
Leo E
  • 709
  • 9
  • 16

1 Answers1

3

Try this code:

import jsonlines


with jsonlines.open('input.jsonl') as reader, jsonlines.open('output.jsonl', mode='w') as writer:
    for obj in reader:
        if obj['name'] == 'Alice':
            obj['age'] = 25
        writer.write(obj)

It will copy all lines of input.jsonl to output.jsonl and change the age field to 25 when the name field is Alice

Cloudomation
  • 1,597
  • 1
  • 6
  • 15
  • Thanks! It works and is an elegant solution! I did not realize you could open in two modes with comma separation. It is just unfortunate a separate file has to be created. But that might be a safer way to go about it. – Leo E Apr 01 '19 at 17:22
  • you can open in rw mode but you need to seek() back to the wanted position. – LtWorf Apr 01 '19 at 17:34
  • if you are opening from within the jsonlines library, it seems you are strictly limited to 'r','w','a'. you cannot use any + modes (e.g. 'r+'). any deviation and you unfortunately get this error : `ValueError: 'mode' must be either 'r', 'w', or 'a'` – Leo E Apr 01 '19 at 17:50