How to check the type of a document element (sub document vs list)? "ReqlServerCompileError: Variable name not found in: var_1"

How to check the type of a document element (sub document vs list)? "ReqlServerCompileError: Variable name not found in: var_1"

我通过提供一些额外的功能来扩展 RethinkDb API

例如我简化了表达式

site_ids = r.table('periods')\
            ['regions']\
            .concat_map(lambda row: row['sites'])\
            ['id']

site_ids = f['periods']\
            .unwind('regions.sites.id')

使用能够解析嵌套文档元素路径的自定义 unwind 方法。如果给定路径中的项目是列表,则其条目与 concat_map 连接。否则使用 bracket 符号访问该项目:

def unwind(self, path):
    items = path.split('.')
    cursor = self._cursor
    for item in items:
        is_list = isinstance(cursor[item].run().next(), list)
        if is_list:
            cursor = cursor.concat_map(lambda row: row[item])
        else:
            cursor = cursor[item]

    return self.wrap(self._f, cursor)

=> 如何改进类型检查以确定元素是否为列表? 检查不需要额外的 .run(),它应该可以工作在主查询和子查询中。

我当前使用表达式

的实现
is_list = isinstance(cursor[item].run().next(), list)

等“主要查询”中工作正常
result = f['periods'] \
 .unwind('regions.sites.plants.product.process.technologies')\
 .populate_with('periods', 'technologies')\
 .sum('specific_cost_per_year') \
 .run()

它在子查询中不起作用,例如在映射函数中:

def period_mapper(period):
    return {
         'year': period['start'],
         'site_ids': f.wrap(period).unwind('regions.sites.id')
    }


f.table('periods')\
 .map(period_mapper)\
 .run()

我收到错误

rethinkdb.errors.ReqlServerCompileError: Variable name not found in:
var_1['regions']
^^^^^  

因为我无法.run()查询传递的变量参数“period”。

我尝试用 r.branch 替换 if-then-else 条件,但这没有帮助。

=> 如何更好地根据当前光标内容的类型选择运算符?

我选择的 class 包装 RethinkDb 游标的代码:

from rethinkdb.ast import RqlQuery


# needs to inherit from RqlQuery for the json serialization to work
class AbstractSelection(RqlQuery):

    def __init__(self, f, cursor):
        self._f = f
        self._cursor = cursor

    def __getitem__(self, identifier):
        cursor = self._cursor[identifier]
        return self.wrap(self._f, cursor)

    def __repr__(self):
        return self._cursor.__repr__()

    def __str__(self):
        return self._cursor.__str__()

    def build(self):
        return self._cursor.build()

    @property
    def _args(self):  # required for json serialization
        return self._cursor._args

    @property
    def optargs(self):  # required for json serialization
        return self._cursor.optargs

    def wrap(self, r, cursor):
        raise NotImplemented('Needs to be implemented by inheriting class')

    def unwind(self, path):
        items = path.split('.')
        cursor = self._cursor
        for item in items:
            is_list = isinstance(cursor[item].run().next(), list)
            if is_list:
                cursor = cursor.concat_map(lambda row: row[item])
            else:
                cursor = cursor[item]

        return self.wrap(self._f, cursor)

    def pick(self, path, query):
        return self.unwind(path).get(query)

    def populate(self, collection_name, path):
        return self.map(lambda identifier:
                        self._f[collection_name]
                        .pick(path, {'id': identifier})
                        )

    def get(self, query):
        cursor = self._cursor.filter(query)[0]
        return self.wrap(self._f, cursor)

    def to_array(self):
        return [item for item in self._cursor]

我设法将 type_ofbranch 结合使用。使用括号符号 returns a STREAM 访问项目,在使用 type_of 检查 'ARRAY' 类型之前,我必须使用 [0] 获取第一个项目。如果 属性 不是数组,这也有效:

def unwind(self, path):
    items = path.split('.')
    cursor = self._cursor
    r = self._f._r
    for item in items:
        cursor = r.branch(
            cursor[item][0].type_of() == 'ARRAY',
            cursor.concat_map(lambda row: row[item]),
            cursor[item]
        )

    return self.wrap(self._f, cursor)