【问题标题】:How to Skip Non Existent keys using Python and MongoDB without KeyErrors如何在没有 KeyErrors 的情况下使用 Python 和 MongoDB 跳过不存在的键
【发布时间】:2015-12-28 13:14:15
【问题描述】:

我使用 MongoDB 存储来自嵌入式设备的少量事件详细信息,并使用 Django 作为数据周围的 Web 应用程序包装器。 device_events 集合具有以下类型的记录:

{"key1": value1,
 "key2": value2,
 "key3": value3, 
 "key4" : {
    "type" : "Point", 
    "coordinates" : [
        87.55092545050022, 
        25.037010399709558
    ]
}, 
 "key5": value5,
}

在同一个集合中,很少有记录可能属于另一种类型:

  {"key9": value9,
     "keyx": valuex,
     "key3": value3, 
     "key4" : {
        "type" : "Point", 
        "coordinates" : [
            87.55092545050022, 
            25.037010399709558
        ]
    }, 
     "key5": value5,
    } 

当我查询集合中的所有记录时,我会得到所有字典的列表。我想使用 map-lambda 仅获取必填字段数据。

现在的问题是,一条记录存在的字段很少,很少有字段不存在。无论是否存在,我都需要在报告中显示该字段,如果键不存在,则可能显示为空/零。

我的地图功能是:

data ={
        "data" : map(
            lambda m: {
                "id": m["key1"], "longitude": m["key4"]["coordinates"][0], "latitude": m["key4"]["coordinates"][1],"active_status" : m["keyx"]
            },
            all_devices
        )
    }

抛出,KeyError: 'id'。

我需要将它用于包含大量数据的报告,需要具有最小开销的高效解决方案。 [我的意思是在这种情况下检查列表中的每个字典的每个键并不是最佳解决方案。]

提前致谢!!

【问题讨论】:

  • 您能否详细说明您的短语“一条记录存在的字段很少,因为很少有字段不存在。我需要在报告中显示该字段,无论是否存在,如果键不存在,则可能为空/零现在。”
  • 你能举个真实的例子吗,我以简化的方式(我理解)尝试了你的代码,没有任何问题/错误。
  • 嗨,key1 存在于第一个字典中,而它不存在于第二个字典中。当我也尝试为第二个字典映射 key1 时,它会抛出 KeyError。
  • 如果你必须检查字典中是否存在键,那么我会使用完整的函数而不是内联函数,因为它很清楚。
  • 您是否建议检查列表的每个字典中是否存在键?它在大量字典中是最优的吗?

标签: python django mongodb dictionary


【解决方案1】:

正如我在评论中所说,如果您必须检查字典中是否存在键,我不会使用单行。

我相信最快的方法是使用 try/except:

def my_func(some_dict):
    out_dict = {}
    try:
        id = some_dict['key1']
    except KeyError:
        id = None
    try:
        long = some_dict["key4"]["coordinates"][0]
    except KeyError:
        long = None
    try:
        lat = some_dict["key4"]["coordinates"][1]
    except KeyError:
        lat = None
    try:
        act = some_dict["keyx"]
    except KeyError:
        act = None
    return {"id": id, "longitude": long, "latitude": lat,"active_status" : act}

data ={"data" : map(my_func,all_devices)}

如果您仍然想要“单线”,那么您可以执行以下操作:

data ={
        "data" : map(
            lambda m: {
                "id": m["key1"] if "key1" in m else None,
                "longitude": m["key4"]["coordinates"][0]  if "key4" in m else None,
                "latitude": m["key4"]["coordinates"][1]  if "key4" in m else None,
                "active_status" : m["keyx"]  if "keyx" in m else None
            },
            all_devices
        )
    }

data ={
        "data" : map(
            lambda m: {
                "id": ((if "key1" in m) and m["key1"]) or None,
                "longitude": ((if "key4" in m) and m["key4"]["coordinates"][0]) or None,
                "latitude":((if "key4" in m) and  m["key4"]["coordinates"][1]) or None,
                "active_status" : ((if "keyx" in m) and m["keyx"]) or None
            },
            all_devices
        )
    }

【讨论】:

  • 您是否建议检查列表的每个字典中是否存在键?它在大量字典中是最优的吗?
  • 我建议使用try/except 子句。如果密钥存在,那将尝试使用该值(而不尝试检查其是否存在)。最佳方案是根本不必调用函数,但我不确定循环是否会更好。也许使用迭代器?您搜索最有效的方法而不是最容易理解的方法的限制是什么?
  • style 的角度来看,列表推导比使用 maplambda 更受欢迎,因为它们更清晰。
【解决方案2】:

由于您想让您的映射保持简单,您必须确保在应用映射之前数据是完整的。

如果您可以控制进入数据库的内容,请确保在其中添加必填字段。

否则,请在从数据库中提取它们之后但在运行 map 之前将缺少的键添加到字典中:

def checker(d):
    for k in ["key1", "key4", "keyx"]:
        if k not in d:
            d[k] = None  # or 0, or ''. Whatever works for you.

data = [checker(d) for d in data]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多