根据How do I update Array Elements matching criteria in a MongoDB document?
我想要插入数组元素,所以如果不匹配则插入它,否则更新它。
我在这个问题上尝试了答案,如果数组元素已经存在,它可以正常工作。如果元素不存在,那么它会在数组字段下创建一个子元素“
。”我的Mongo结构如下:
Widget (collection)
--Name
--Properties (array)
--Name
--Value
我的应用程序从WebService调用中获取Widget Name和Properties列表。我希望迭代提供的属性并在Name已经存在的情况下更新MongoDB中的值,或者如果不存在则将新属性插入到Properties数组中。
答案 0 :(得分:10)
如果没有某些应用程序端逻辑,则无法使用单个更新。请注意,upsert作为一项功能与此特定问题无关,除非您想要自动创建新的Widget文档(如果不存在所提供的名称)。
您遇到的问题是没有任何功能允许您根据数组元素的存在执行两个不同的更新。您唯一的两个选择是:
答案 1 :(得分:4)
您不能以原子方式插入数组元素。但是,如果您可以重新构建文档以使用对象而不是数组,那么这在原子上是可行的。使用您的符号,结构将是
Widget (collection)
--Name
--Properties
--Property1
--Property2
.
:
示例文档将是
{
name: 'widget-1',
properties: {
'property-1': 100,
'property-2': 200
}
}
要为值为300的名为“property-3”的项目竖起,您需要
db.widgets.update(
{ name: 'widget-1' },
{ $set: { 'properties.property-3': 300 } }
)
一个缺点是查询字段名称(使用$exists
查询运算符)需要扫描。您可以通过添加存储属性名称的额外数组字段来解决此问题。可以正常索引和查询该字段。 Upserts成为
db.widgets.update(
{ name: 'widget-1' },
{
$set: { 'properties.property-3': 300 },
$addToSet: { propertyNames: 'property-3' }
}
)
(请记住$addToSet
是O(n)。)删除属性时,您也必须从数组中提取它。
db.widgets.update(
{ name: 'widget-1' },
{
$unset: { 'properties.property-3': true },
$pull: { propertyNames: 'property-3' }
}
)
答案 2 :(得分:1)
至少在php中它对我有用,尝试采用你的语言。 你需要你的收藏品如下:
{Name: x, Properties: {name1:value1, name2:value2, name3:value3}}
foreach ($Properties as $name => $value)
{
$propertiesArray["Properties.$name"] = $value;
}
$criteria = array('Name' => $name);
$operation = array('$set' => $propertiesArray);
$options = array('upsert' => true);
$collection = $this->_dbh->selectCollection('Widget');
$collection->update($criteria, $operation, $options);
如果不存在则插入新名称并更新已存在的名称