13

I'm trying to insert a transaction into the transaction list.

This is the document:

{
    "_id" : ObjectId("5cb26787c3eb6c8229a92954"),
    "first_name" : "testing",
    "last_name" : "testing",
    "ssn" : "123456789",
    "address" : "123 testing st",
    "account" : {
        "account_number" : 32362897,
        "last_access_timestamp" : "2019-04-13 18:49:43",
        "account_type" : [
            {
                "checking" : {
                    "balance" : 0,
                    "transaction" : [ ]
                }
            },
            {
                "saving" : {
                    "balance" : 0,
                    "transaction" : [ ]
                }
            }
        ]
    }
}

The ssn is supposed to be unique so I'm using that as the matching criteria. This is the query I'm using to insert into the checking transaction list:

db.customer.update({'ssn': '123456789'},
                    {'$push': {'account.account_type.checking.transaction': {
                         'amount': 120,
                         'transaction_type': 'deposit',
                         'timestamp': '11:11:11'
                     }}})

The expected outcome is:

{
    "_id" : ObjectId("5cb26787c3eb6c8229a92954"),
    "first_name" : "testing",
    "last_name" : "testing",
    "ssn" : "123456789",
    "address" : "123 testing st",
    "account" : {
        "account_number" : 32362897,
        "last_access_timestamp" : "2019-04-13 18:49:43",
        "account_type" : [
            {
                "checking" : {
                    "balance" : 0,
                    "transaction" : [{
                         "amount": 120,
                         "transaction_type": "deposit",
                         "timestamp": "11:11:11"
                     } ]
                }
            },
            {
                "saving" : {
                    "balance" : 0,
                    "transaction" : [ ]
                }
            }
        ]
    }
}

This is the error message I'm getting:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 28,
        "errmsg" : "Cannot create field 'checking' in element {account_type: [ { checking: { balance: 0, transaction: [] } }, { saving: { balance: 0, transaction: [] } } ]}"
    }
})
John
  • 133
  • 1
  • 1
  • 4
  • 7
    `account_type` is an array. mongo is lenient when querying fields on objects in arrays, but for updates you need to specify what element of the array you are updating. Something like `$push: { 'account.account_type.0.checking.transaction': ... }` – kmdreko Apr 13 '19 at 23:38
  • @kmdreko You seem to be referencing a similar statement to what the very first code block in the linked duplicate says, however if you read the text of the answer around that code block you would see that using absolute index notation such as `account_type.0` is actually **NOT** what you want to do here. – Neil Lunn Apr 14 '19 at 03:54
  • Modern MongoDB releases allow statements like `.updateOne({ "ssn" : "123456789", "account.account_type.checking": { "$exists": true } }, { "$push": { "account.account_type.$[elem].checking.transaction": { "amount": 120, "transaction_type": "deposit", "timestamp": "11:11:11" } }, { "arrayFilters": [{ "elem.checking": { "$exists": true } }] })`. But as the main linked content says, you really should consider NOT nesting array content and flattening the structure. – Neil Lunn Apr 14 '19 at 04:01
  • You can also get away with `.updateOne({ "ssn" : "123456789", "account.account_type.checking": { "$exists": true } }, { "$push": { "account.account_type.$.checking.transaction": { "amount": 120, "transaction_type": "deposit", "timestamp": "11:11:11" } })` using a simple positional `$` because it's a `$push` and you don't need to match on the "inner" array. This will not be true for a `$set` or any other modification of the "inner array" elements, and you would need the positional filtered `$[]` syntax as demonstrated on the primary duplicate answer and comment above. – Neil Lunn Apr 14 '19 at 04:03
  • 2
    You can use `$[]` `'account.account_type.$[].checking'` – CherryBlossom Jan 05 '22 at 00:03

0 Answers0