我有一个看起来像这样的MongoDB集合:
{
"_id" : { "customerName" : "Bob", "customerPhone" : "123-456-7890"},
"purchases": ["A", "B", "C", "D"]
}
基本上,_id是一对关于客户的唯一密钥,而购买是客户购买的项目的数组。
我还有一个PySpark DataFrame,我想将其推入此集合,其中包含我想要更新此特定文档的信息。
df.write.format("com.mongodb.spark.sql.DefaultSource").mode("append") \
.option("spark.mongodb.output.uri", "mongodb://localhost:27017/customer.purchases").save()
问题在于,如果我要更新此文档,我想为Bob添加新购买,则只会在purchases
中附加不存在的商品,而不是追加所有商品。
因此,我现在最终做的就是我只需要调用rdd.collect()
将整个事物转换为列表而不使用架构将其转换为DataFrame。然后在检查密钥是否存在的同时逐个插入所有内容;这使得这部分变得很慢,并且当RDD的查询变大时需要大量内存。
对于版本:
PySpark:2.2 MongoDB:3.0.15 Mongo Spark Connector:2.2.1有没有人可以使用数据框将数组中的所有元素追加到MongoDB集合中? 此外,如果我有任何遗漏或其他我应该做的事情,请告诉我。 谢谢!
答案 0 :(得分:0)
您需要更改文档的data models或架构。这里的重要部分是_id
关键字段。字段名_id
保留用作主键;它的值在集合中必须是唯一的,是不可变的,并且可以是除数组之外的任何类型。
在您的情况下,_id
字段的值是可变的,实际上这是您尝试更新的内容。作为建议,您可能希望将其更改为:
{ "_id" : <unique identifier>
"customerName" : "Bob",
"customerPhone" : "123-456-7890",
"purchases": ["A", "B", "C", "D"]
}
您可以使用ObjectId的默认_id
值作为唯一标识符。
在_id
字段上有唯一标识符之后,让我们谈谈更新操作。自MongoDB Spark Connector v1.1 +(当前版本为2.2)以来,如果数据帧在写入期间包含_id
字段,则数据将为upsert-ed。这意味着将更新具有相同_id值的任何现有文档,并且将插入集合中没有现有_id值的新文档。
奖金回合:
您还需要为purchases
字段找到更好的架构。如果数组长度未定义,可能会在将来产生问题。即鲍勃一年内购买了1000件商品。
请更新您的MongoDB服务器版本(版本3.0.x是2015年),目前的稳定版本是3.4,下个月将发布3.6版本。