将多个键值匹配到 TinyDB 中的数据库条目?

Match multiple keys values to database entry in TinyDB?

我很难确定是否可以使用 TinyDB 一次检查多个键值。目前,我可以通过在 if 语句中使用 and 来检查多个字段,如下所示:

def check_table(FNAME="NULL", LNAME="NULL", MNAME="NULL"):
    if (HHK_STAFF.search(Query().FNAME == FNAME)) != [] \
    and (HHK_STAFF.search(Query().MNAME == MNAME)) != [] \
    and (HHK_STAFF.search(Query().LNAME == LNAME)) != []:
        print(HHK_STAFF.search(Query().FNAME == FNAME)[0])
    else:
        print("user does not exist")

check_table(FNAME="Some", MNAME="Random", LNAME="Person")

它可以满足我的需求,但它接缝笨重。我希望 TinyDB 中有一些内置的东西可以执行相同的功能而不需要许多 and 语句。

我正在尝试做类似的事情:

HHK_STAFF.search(where(("FNAME", "MNAME", "LNAME")) == (FNAME, MNAME, LNAME)))

问题:

  1. 有没有人知道使用 Query() the table 查询多个键值而不是一次只查询一个键值的方法?

  2. 你能给这个信息列出一个link吗?我很难找到这条信息(如果它存在的话)。

这是我使用 TinyDB 的简单版本:

from tinydb import TinyDB, Query


#~~~~~~~~~~~~~~~~~~~~~~< CURRENT DBPATH >~~~~~~~~~~~~~~~~~~~~~~
DB = TinyDB('./DB_PATH/HHK_DB.json')
#~~~~~~~~~~~~~~~~~~~~~~< CURRENT TABLES >~~~~~~~~~~~~~~~~~~~~~~
HHK_STAFF = DB.table("HHK_STAFF")

HHK_STAFF.insert({'EMPLOYEE_ID':'00000001', 'FNAME': 'Some', 'LNAME':'Person', 'MNAME':'Random'})


def check_table(FNAME="NULL", LNAME="NULL", MNAME="NULL"):
    if (HHK_STAFF.search(Query().FNAME == FNAME)) != [] \
    and (HHK_STAFF.search(Query().MNAME == MNAME)) != [] \
    and (HHK_STAFF.search(Query().LNAME == LNAME)) != []:
        print(HHK_STAFF.search(Query().FNAME == FNAME)[0])
    else:
        print("user does not exist")

check_table(FNAME="Some", MNAME="Random", LNAME="Person")

结果:

{'EMPLOYEE_ID': '00000001', 'FNAME': 'Some', 'LNAME': 'Person', 'MNAME': 'Random'}

您可以使用 python 内置 all 来实现更短、更灵活的示例代码:

def check_table2(**query):
    if all(HHK_STAFF.search(getattr(Query(), k) == v) 
           for k, v in query.items()):
        print(HHK_STAFF.search(Query().FNAME == query['FNAME'])[0])
    else:
        print("user does not exist")

但您应该确定这确实是您想要的。对应的英文是

"If someone with this last name exists, and someone with this first name exists, and someone with this middle name exists, regardless of whether they're all the same someone, return the person with the matching first name."

换句话说,如果我现在将另一个人添加到您的数据库中

HHK_STAFF.insert({'EMPLOYEE_ID':'00000002', 
                  'FNAME': 'Anne', 
                  'LNAME':'Person',
                  'MNAME':'Other'})

上面的函数将为查询return提供一些东西

check_table(FNAME="Some", MNAME="Other", LNAME="Person")

即使Some的中间名是"Random"而不是"Other",只是因为系统上存在其他人的中间名是"Other"

您可能想利用 Query 的覆盖 __and__ operator 来查找具有您要查询的所有姓名的个人:

q = Query()
HHK_STAFF.search((q.FNAME=="Anne") & 
                 (q.MNAME=="Other") & 
                 (q.LNAME=="Person"))

或者,对于像我上面那样使用键值的东西,使用 functools.reduce:

from functools import reduce

def user_matching_all(**query):
    q = Query()
    out = HHK_STAFF.search(reduce(lambda x, y: x & y,
                                  [getattr(q, k) == v
                                   for k, v in query.items()]))
    if out:
        print(out)
    else:
        print("user does not exist")

根据 Advanced Usage — TinyDB 3.8.1.post1 documentation,逻辑与将如下所示:

q = Query()
HHK_STAFF.search((q.FNAME == FNAME) & (q.MNAME == MNAME) & (q.LNAME == LNAME))

根据 git blame of tinydb/queries.py,自第一个版本以来它一直可用。