【问题标题】:Nested JSON array not updating in DB嵌套的 JSON 数组未在数据库中更新
【发布时间】:2020-07-08 15:11:14
【问题描述】:

使用:Python 3.7.3、SQLAlchemy 1.3.13 和 sqlite。

我正在努力将以下 JSON 结构中的数据附加到我的数据库中的 JSON 字段中。

这是我正在寻求实现的事情,但我正在努力做的是添加:“第二条消息”、“第三条消息”等......

data = {
    "title":'some title',
    "status": "some status",
    "logs": [
        [mytimestamp, "First message"],
        [mytimestamp, "Second message"],
        [mytimestamp, "Third message"]
    ]
}

将上述数据结构插入数据库工作正常。像这样:

tablename = Tablename(someint=1, data=data)
try:
    db.session.add(tablename)
    db.session.commit()  <--- success every time
except:
    print('Error creating record')

更新和修改顶级项目(例如“标题”、“状态”)我可以毫无问题地完成。我什至可以添加额外的。

tablename = Tablename.query.get(id)
try:
    tablename.data = newdata <--- newdata is where the problem is
    tablename.someint = 2 <--- this always updates without problem
    db.session.commit()
except:
    print('Error updating record')

但是当涉及到将额外的数组项添加到“日志”时,这是完全奇怪的地方......数据库记录将更新,但我的 JSON 字段除外,但它同样不会引发异常,它只是更新其他数据库列但忽略我的 JSON 字段。

我尝试了 append()、update() 的各种方法,即使这样也可以tablename.data = {**olddata, **newdata},但仅适用于顶级项目。一旦我尝试在“日志”中操作数据,那么它:

  • 要么:错误,因为我试图错误地操纵数据(很公平)

  • 或者:静默忽略我正在更新数据列的事实,即使当我打印(newdata)和我想放入数据库的输出值时,我可以看到它是正确的......但数据库只是忽略它!

我没有得到的是data 首先会很高兴地插入数据库,然后我可以找到更新对象的方法(即使它很丑,在这个阶段我只是希望它工作!)我通过查询离开数据库但我不明白为什么我可以将结果对象打印到 CLI 并且它看起来不错但数据库只是默默地忽略它(someint 总是在静默期间更新失败)!如果无效,至少抛出一个错误?

有人有什么想法吗?您将如何将行附加到“日志”?

--- 重要更新 ---

由于我昨天得到的结果对我来说完全没有逻辑意义,所以我放弃了这个话题,今天又带着新的眼光回来了。这是我到目前为止所做和发现的,我的发现不令人愉快,但至少我有一个现在似乎有效的解决方案:在数据库中使用 VARCHAR 字段而不是 JSON 字段.

这就是我得出结论的方式:

我在我的数据库表中添加了一个额外的列,所以现在我有了:

data1 -> type: JSON
data2 -> type: VARCHAR

这是我的测试代码:

# Get the data
tablename = Tablename.query.get(id)
d1 = tablename.data1 # from JSON field
d2 = json.loads(tablename.data2) # from VARCHAR field

# Append a log message
logs = d1['logs'] # <--- See note 1 below
# logs = d2['logs'] # <--- See note 2 below
logs.append([mytimestamp, message])
newlogs = {'logs': logs}

# Update database record with new data
tablename.data1 = {**d1, **newlogs} # Into JSON field
tablename.data2 = json.dumps({**d2, **newlogs}) # Into VARCHAR field
db.session.commit()

注意 1:如果我使用 d1 作为源(即:来自 JSON 列),则 data1 字段不会更新为新消息,但 data2 字段会更新!

注意 2:如果我使用 d2 作为源(即:来自 VARCHAR 列),那么 data1data2 字段都会成功更新为新消息。

【问题讨论】:

    标签: python json python-3.x sqlite sqlalchemy


    【解决方案1】:

    已找到解决方法/解决方案!

    根据文档,问题实际上是预期的行为。 SQLAlchemy documentation 状态,我引用:

    使用 ORM 时检测 JSON 列中的更改: JSON 类型在与 SQLAlchemy ORM 一起使用时,不会检测到结构的就地突变。为了检测这些,必须使用 sqlalchemy.ext.mutable 扩展。此扩展将允许对数据结构进行“就地”更改以产生将被工作单元检测到的事件。有关字典的简单示例,请参见 HSTORE 中的示例。

    缺点是实现上述内容相对复杂,更重要的是“昂贵”。但是,我发现,一个更简单的解决方案是在您想要进行更改时始终更新顶级项目。例如,每次您想将新项目添加到logs 数组中时,更新下面示例中的last_updated 的值将导致更新完整记录。不这样做将意味着您更新的 JSON 数据将丢失,甚至 try: except: 也不会告诉您。

    data = {
        "title":'some title',
        "status": "some status",
        "last_updated": int(floor(time.time() * 1000)),
        "logs": [
            [mytimestamp, "First message"],
            [mytimestamp, "Second message"],
            [mytimestamp, "Third message"]
        ]
    }
    

    【讨论】:

    猜你喜欢
    • 2018-05-15
    • 2019-12-26
    • 2021-04-17
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2019-11-02
    相关资源
    最近更新 更多