Adding/Updating object to/in nested array in mongodb
<p>I have a document:</p>

<pre><code>{
  "_id": "57d421bbbc44538f0634081c",
  "in_date": "1473724800",
  "bboxes": [
      { "bbox_index": "4124432432311", "data": {} },
      { "bbox_index": "4124435342332", "data": {} },
      ...
  ]
}
</code></pre>

<p>I'm trying to update entire object found in <code>bboxes</code> with specific <code>bboxes.bbox_index</code>:</p>

<pre><code>bbox_index = 4124432432311
in_date = 1473724800

self.db['my_table'].update(
    {
        'in_date': in_date,
        'bboxes.bbox_index': bbox_index
    }, 
    {
        '$set': {'bboxes.$': dict(item)}
    },
    upsert=True
)
</code></pre>

<p>I expect this object <code>{ "bbox_index": "4124432432311", "data": {} }</code> to be replaced with <code>dict(item)</code></p>

<p>This works fine when object with required <code>bbox_index</code> already exists. When it doesn't exist, I get <code>The positional operator did not find the match needed from the query. Unexpanded update: bboxes.$</code></p>

<p>In order to make it work I have to do the same query but instead of <code>$set</code> do <code>{'$push': {'bboxes': dict(item)}}</code>. Of course, this doesn't work well when I do already have required object in database. In this case I'm pushing same object again. Possible solution would be to check for the object before updating it but I wanted to make it in one single expression. I thought <code>upsert=True</code> was made exactly for this purpose. Is there any way to do what I want?</p>

<p>Instead of using <code>$push</code>, you can use <code>$addToSet</code> which will insert a new entry in the array only if the entry doesn't exist yet.</p>

<p>To paraphrase the relevant manual page <a href="https://docs.mongodb.com/manual/reference/operator/update/addToSet/" rel="nofollow">https://docs.mongodb.com/manual/reference/operator/update/addToSet/</a>:</p>

<blockquote>
  <p>The <strong>$addToSet</strong> operator adds a value to an array unless the value is already present, in which case <strong>$addToSet</strong> does nothing to that array.</p>
</blockquote>

python mongodb pymongo