开发者

mongodb php finding a subobject and removing it, $inc other subobject

开发者 https://www.devze.com 2023-02-01 06:25 出处:网络
I\'m trying to delete the subobject \'apples\' from my documents and update the \'fruitInventory\' property, decrease by the amount of apples.

I'm trying to delete the subobject 'apples' from my documents and update the 'fruitInventory' property, decrease by the amount of apples.

I'm confused on how to proceed, should I use dot notation or do a full text search for apples? I don't know if this matters but you can assume apples will always be in field 1.

// Document 1 
{
    "1": {
        "apples": 3,
        "fruitInventory": 21,
        "oranges": 12,
        "kiwis": 3,
        "lemons": 3
    },
    "2": {
        "bananas": 4,
        "fruitInventory": 12,
        "oranges": 8,
    },
    "_id": "1"
}

// Document 2
{
    "1": {
        "apples": 5,
        "fruitInventory": 10,
        "oranges": 2,
        "pears": 3
    },
    "2": {
        "bananas": 4,
        "fruitInventory": 6,
        "cherries": 2,
    },
    "_id": "2"
}

Result should be like this:

// Document 1 
{
    "1": {
        "fruitInventory": 18,
        "oranges": 12,
        "kiwis": 3,
        "lemons": "3"
    },
    "2": {
        "bananas": 4,
        "fruitInventory": 12,
        "oranges": 8,
    },
    "_id": "1"
}

// Document 2
{
    "1": {
        "fruitInventory": 5,
        "oranges": "2",
        "pears": "3"
    },
    "2": {
        "bananas": 4,
        "fruitInventory": 6,
        "cherries": 2,
  开发者_运维技巧  },
    "_id": "2"
}

Thanks in advance for your help.


In the MongoDB query language there is no way to update a document using information from the document. In other words, there is no way to increment one property with a value from another property. To be specific: there is no way to increment the fruitInventory by X where X is the value of the apples property as an atomic operation.

The way I would implement this, while avoiding races, is with two findAndModify operations (seen here in Mongo shell syntax):

var fruit = db.fruit.findAndModify({
 query: {locked: {$ne: true}, "1.apples": {$exists: true}},
 update: {$set: {locked: true}}
});

var fruitInventory = fruit["1"]["fruitInventory"];
var apples = fruit["1"]["apples"];

db.fruit.findAndModify({
  query: {"_id": fruit["_id"]},
  update: {
    $set: {"1.fruitInventory": fruitInventory + apples}, 
    $unset: {locked: false, "1.apples": true}
  }
});

What happens is this: first I find a document which is not locked (more on this later), and has an 1.apples property. The document is returned and updated to get a locked property as a single atomic operation. Since the document now has a locked property it will not be found by the same query, so this query can be run multiple times in parallel without any risk of modifying the same document twice.

I then extract the 1.fruitInventory and 1.apples, to simplify the next expression.

The second findAndModify updates the 1.fruitInventory property with the new sum, and unsets the 1.apples property, as well as the locked property (to return the document to its previous, unlocked, state).

To update all documents you will have to run this code over and over again until the first findAndModify returns null (meaning there are no documents matching the query).


Use $unset with a multi-update:

> db.whatever.update({}, {$unset : {"1.apples" : true}}, false, true)

On a higher-level note, you might want to use richer data types (e.g., ints should usually be stored as ints, unless there's a good reason for them not to be).


MongoDB doesn't allow you to modifier exist scheme of document.For this task you should to remove document (or element of set). and Insert new modified document(or element of set)

0

精彩评论

暂无评论...
验证码 换一张
取 消