使用:带sqlite的Python 3.7.3,SQLAlchemy 1.3.13。
我正在努力将以下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)和要放入db的输出值时也可以看到它是正确的...但是数据库只会忽略它!
我没有得到的是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
字段会更新! / p>
注2:如果我使用d2
作为来源(即:从VARCHAR列),则data1
和data2
字段都将成功更新为新消息。
答案 0 :(得分:1)
已找到解决方法/解决方案!
根据文档,问题实际上是预期的行为。 SQLAlchemy documentation的状态,我引用:
使用ORM时检测JSON列中的更改 : JSON类型与SQLAlchemy ORM一起使用时,不会检测到该结构的就地突变。为了检测到这些,必须使用sqlalchemy.ext.mutable扩展名。此扩展将允许对数据结构进行“就地”更改以产生事件,这些事件将由工作单元检测到。有关涉及字典的简单示例,请参见HSTORE上的示例。
缺点是实施上述操作相对复杂,更重要的是“昂贵”。但是,我发现一种更容易,更简单的解决方案是,无论何时要进行更改,都始终更新顶层项目。例如,每次要将新项目添加到last_updated
数组中时,在下面的示例中更新logs
的值都会导致完整记录的更新。否则,将意味着更新后的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"]
]
}