MongoDB: 如果文档不存在,才使用$addToSet/$push添加文档

9
我有一个名为lists的集合,每个文档都有一个members数组。 members数组的每个元素都是一个文档,其中包含一个email属性、一个创建date属性和一些其他元数据。我在members.email上设置了唯一索引,以防止将相同的电子邮件输入到同一列表中两次,但我想保留原始的date值。不幸的是,$addToSet$push似乎都无法实现这一点。

使用$push的示例:

$lists->update(array('_id' => $list['_id'], 'members.email' => array('$ne' => $email)), array('$push' => array('members' => array(
    'email' => $email,
    'date' => new MongoDate(),
    // etc.
))));

同时使用$addToSet:

$lists->update(array('_id' => $list['_id']), array('$addToSet' => array('members' => array(
    'email' => $email,
    'date' => new MongoDate(),
    // etc.
))));

这两个示例由于(我猜)唯一的date值,替换了整个嵌入式文档。是否有可能仅在members.email不存在时才$push“member”文档,或者我需要分两个命令执行?

或者,从可伸缩性的角度考虑,将members放入自己的集合中,并使用类似于parent_list的属性是否更好?

5个回答

5
根据我的经验,你无法使用"$push"或"$addToSet"的原因可能是你的目标"members"可能是一个嵌套对象(或在创建后被转换为嵌套对象)。你只能在嵌套数组上使用$push、$pushAll、$addToSet...
对于我们这些PHP开发人员来说,游标查询总是以数组形式返回数据,检查类似"members"是否为数组或对象的最佳方法是在mongo shell中运行find()并查看结果中的花括号/方括号("{}"或"[]")。
希望这能帮到你。

1
为什么不创建一个集合,其中存储list_id、email和added_date。然后在list_id和email这两个键上创建唯一索引。这将防止插入具有相同list_id和email的记录。
不会有嵌入式文档。您仍然可以通过list_id使用find()函数。

1

使用$ne在查询条件中过滤具有相同电子邮件成员的文档:

$lists->update(array('_id' => $list['_id'],
                     'members.email' => array('$ne' => $email)), 
               array('$addToSet' => array('members' => array(
                     'email' => $email,
                     'date' => new MongoDate(),
                      // etc.
))));

0

是的,这是可能的。请查看mongoDB 高级查询 部分中的$exists运算符。将$exists条件编码到where语句中,仅在成员电子邮件不存在时进行更新。


1
我几乎可以确定$exists不是我正在寻找的解决方案。 - Kevin

0

如果我理解正确的话,可以尝试使用Upsert来更新嵌入式文档(如果有)或插入它(如果没有)。也可以参考this

至于你关于可扩展性的第二个问题,这真的取决于具体情况...将文档嵌入到父级中需要更难的更新和更大的数据获取,但可以减少获取查询次数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接