【问题标题】:Flat file NoSQL solution [closed]平面文件 NoSQL 解决方案 [关闭]
【发布时间】:2020-07-20 03:06:46
【问题描述】:

对于小型项目,SQLite(或类似的)是否有内置的方法来保持 SQL / NoSQL 两全其美,即:

  • 存储在(平面)文件中,如 SQLite(无需客户端/服务器方案,无需安装服务器;更准确地说:除了 pip install <package> 外无需安装其他任何东西)
  • 可以将行存储为dict每行没有共同的结构,如 NoSQL 数据库
  • 支持简单查询

例子:

db = NoSQLite('test.db')
db.addrow({'name': 'john doe', 'balance': 1000, 'data': [1, 73.23, 18]})
db.addrow({'name': 'alice', 'balance': 2000, 'email': 'a@b.com'})
for row in db.find('balance > 1500'):
    print(row)

# {'id': 'f565a9fd3a', 'name': 'alice', 'balance': 2000, 'email': 'a@b.com'}   # id was auto-generated

注意:多年来,我一直对 SQLite 在几行代码中实际上可以实现多少有趣的功能感到惊讶,这就是为什么我要问我在这里描述的内容是否可以通过 SQLite 简单地使用仅使用几个 SQLite 核心功能。

PS:shelve可能看起来像一个解决方案,但实际上它只是一个持久键/值存储,它没有查询/find 功能;还有bsddb(BerkeleyDB for Python)看起来已被弃用,并且没有类似 API 的查询功能。

【问题讨论】:

    标签: python sql database sqlite nosql


    【解决方案1】:

    可以通过使用JSON1 扩展来查询存储在列中的 JSON 数据,是的:

    sqlite> CREATE TABLE test(data TEXT);
    sqlite> INSERT INTO test VALUES ('{"name":"john doe","balance":1000,"data":[1,73.23,18]}');
    sqlite> INSERT INTO test VALUES ('{"name":"alice","balance":2000,"email":"a@b.com"}');
    sqlite> SELECT * FROM test WHERE json_extract(data, '$.balance') > 1500;
    data
    --------------------------------------------------
    {"name":"alice","balance":2000,"email":"a@b.com"}
    

    如果您要经常查询同一个字段,可以通过在表达式上添加索引来提高效率:

    CREATE INDEX test_idx_balance ON test(json_extract(data, '$.balance'));
    

    将在上述查询中使用该索引,而不是扫描每一行。

    【讨论】:

    • 哇,不错的解决方案!然后我猜,它会循环整个 DB来做find('name="john doe"')?我想是这样的,因为 SQLite 必须 json_extract 所有行来测试名称是否匹配,对吗?
    • @Basj 你也许可以用index on an expression 做点什么,但我还没试过。否则,是的,它必须查看每一行 - 请注意,我并没有说这样做是一个的想法,只是它可以做到。 :)
    • 好的,表达式上的索引将适用于json_extract()。
    • 谢谢!在使用CREATE INDEX test_idx_balance ON test(json_extract(data, '$.balance')); 创建索引后,您能否提供一个如何完成查询的示例?
    【解决方案2】:

    SQLite

    • JSON1 扩展和json_extract(见接受的答案)。示例:

      import sqlite3, json  # tested with precompiled Windows binaries from https://www.sqlite.org/download.html (sqlite3.dll copied in C:\Python37\DLLs)
      
      class sqlitenosql:
          def __init__(self, f):
              self.db = sqlite3.connect(f)
              self.db.execute('CREATE TABLE test(data TEXT);')
      
          def close(self):
              self.db.commit()
              self.db.close()
      
          def addrow(self, d):
              self.db.execute("INSERT INTO test VALUES (?);", (json.dumps(d),))
      
          def find(self, query):
              for k, v in query.items():
                  if isinstance(v, str):
                      query[k] = f"'{v}'"
              q = ' AND '.join(f" json_extract(data, '$.{k}') = {v}" for k, v in query.items())
              for r in self.db.execute(f"SELECT * FROM test WHERE {q}"):
                  yield r[0]
      
      db = sqlitenosql(':memory:')
      db.addrow({'name': 'john', 'balance': 1000, 'data': [1, 73.23, 18], 'abc': 'hello'})
      db.addrow({'name': 'alice', 'balance': 2000, 'email': 'a@b.com'})
      db.addrow({'name': 'bob', 'balance': 1000})
      db.addrow({'name': 'richard', 'balance': 1000, 'abc': 'hello'})
      for r in db.find({'balance': 1000, 'abc': 'hello'}):
          print(r)
      # {"name": "john", "balance": 1000, "data": [1, 73.23, 18], "abc": "hello"}
      # {"name": "richard", "balance": 1000, "abc": "hello"}    
      db.close()
      
    • sqlitedictKey: value store in Python for possibly 100 GB of data, without client/serverUse SQLite as a key:value store 中所述 与:

      key = 一个 ID

      value = 我们要存储的字典,例如{'name': 'alice', 'balance': 2000, 'email': 'a@b.com'}

    • 进一步阅读关于使用 JSON 的 SQLite:https://community.esri.com/groups/appstudio/blog/2018/08/21/working-with-json-in-sqlite-databases

    TinyDB

    TinyDB 看起来是个不错的解决方案:

    >>> from tinydb import TinyDB, Query
    >>> db = TinyDB('path/to/db.json')
    >>> User = Query()
    >>> db.insert({'name': 'John', 'age': 22})
    >>> db.search(User.name == 'John')
    [{'name': 'John', 'age': 22}]
    

    但是,文档提到如果我们需要,它不是正确的工具:

    • 从多个进程或线程访问,
    • 为表创建索引,
    • HTTP 服务器,
    • 管理表或类似表之间的关系,
    • ACID 保证

    所以这是一个一半的解决方案:)

    其他解决方案

    看起来也很有趣:WhiteDB

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多