python - 通过 sqlalchemy 映射类在 MySQL JSON 字段中插入键而不执行查询

标签 python mysql sqlalchemy

让我们首先定义我的映射类

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=1data={'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/

相关文章:

mysql - 从 Rails 4.1 的 `:distinct` 中删除弃用的 `Relation#count` 选项

mysql - 两个表之间的 "Join"非常快,而 "Left join"则非常慢(MySQL DB)

php - UTF8 编码的字符串在 MySQL 中无法正确显示

python - Flask-WTF model_form、Sqlalchemy 和外键

python - 如何使用 python 客户端库获取 Pubsub 中存在的未传递消息(指标 api)的数量?

Python 请求 : Generating a specific token (__cf_bm)

Python HDFS 蛇咬 : Methods work only with print

python - 在 Python 3 中复制属性的更优雅的方式

python - 为什么这个 group_by/count 查询返回一个元组数组?

python - 使用 SQLAlchemy 和多处理卡在 Python 脚本中