让我们首先定义我的映射类
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.types import JSON
from sqlalchemy.ext.mutable import MutableDict
from sqlalchemy import Column, Integer
base = declarative_base()
class MinimalExample(Base):
__tablename__ = 'users'
id = Column(Integer)
data = Column(MutableDict.as_mutable(JSON))
假设我的表格中有一行包含 id=1
和 data={'key_0': 1}
我可以很容易地通过 session
对象请求它
first_row = session.query(MinimalExample)\
.filter(MinimalExample.id==1)\
.first()
从那里我可以以任何我想要的方式修改 JSON 字段并更新数据库:
first_row.data['key_2'] = 1
session.commit()
上面的代码有效(因为我们将 JSON 字段标记为可变字典,所以我们不必手动将其标记为脏)
session.query(MinimalExample.data)\
.filter(MinimalExample.id==1)\
.first()
>>> {'key_0': 1, 'key_2': 1}
但这意味着我必须在本地计算机上查询我想要修改的所有行,这太慢了/我没有足够的内存。
我正在寻找一种使用sqlalchemy.update
函数来获得相同结果的方法
这是我已经尝试过的:
from sqlalchemy import update
stmt = update(MinimalExample)
.where(MinimalExample.id=1)\
.values(MinimalExample.data={'key_1': 1})
session.execute(stmt)
session.commit()
这将用字典 {'key_1': 1}
替换我行中的 data
字段
与此类似的东西似乎是可行的方法:
(编辑:找到了一种方法来纠正我以前的代码,这样它就不再引发错误,只需将对象放入字典即可)
stmt = update(MinimalExample)
.where(MinimalExample.id=1)\
.values({MinimalExample.data['key_1']:1})
看这个语句的字符串看起来不错
str(stmt)
>>> 'UPDATE users SET data[:data_1]=:param_1 WHERE users.id = :id_1'
但是执行此语句会导致 ProgrammingError: (MySQLdb._exceptions.ProgrammingError) (1064, 'You have an error in your SQL syntax
...
对此有什么想法吗?如果我可以同时更新多行,则会获得奖励分
最佳答案
要更新 MySQL 中的 JSON 列,您需要使用 JSON_SET()
函数(具体信息请参阅 here),例如工作查询如下所示:
UPDATE users SET data = JSON_SET(data, "$.key_1", 1) WHERE id = 1;
在 SQLAlchemy 中模拟:
qry = (
update(MinimalExample)
.where(MinimalExample.id == 1)
.values(
{"data": func.JSON_SET(MinimalExample.data, "$.key_1", 1)}
)
)
s.execute(qry)
s.commit()
这是从创建表到提交的日志,正如您所看到的,没有发出 SELECT:
2019-10-11 09:37:01,672 INFO sqlalchemy.engine.base.Engine
CREATE TABLE users (
id INTEGER NOT NULL AUTO_INCREMENT,
data JSON,
PRIMARY KEY (id)
)
2019-10-11 09:37:01,684 INFO sqlalchemy.engine.base.Engine {}
2019-10-11 09:37:01,708 INFO sqlalchemy.engine.base.Engine COMMIT
2019-10-11 09:37:01,716 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-10-11 09:37:01,718 INFO sqlalchemy.engine.base.Engine INSERT INTO users (id, data) VALUES (%(id)s, %(data)s)
2019-10-11 09:37:01,718 INFO sqlalchemy.engine.base.Engine {'id': 1, 'data': '{"key_0": 1}'}
2019-10-11 09:37:01,720 INFO sqlalchemy.engine.base.Engine COMMIT
2019-10-11 09:37:01,723 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-10-11 09:37:01,724 INFO sqlalchemy.engine.base.Engine UPDATE users SET data = JSON_SET(data, "$.key_1", 1) WHERE id = 1;
2019-10-11 09:37:01,724 INFO sqlalchemy.engine.base.Engine {}
2019-10-11 09:37:01,725 INFO sqlalchemy.engine.base.Engine COMMIT
关于python - 通过 sqlalchemy 映射类在 MySQL JSON 字段中插入键而不执行查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58324287/