Question

Consider the following document:

{
    "entity_id" : 10,
    "features" : 
    [ 
    {
        "10" : "Test System 2"
    }, 
    {
        "20" : "System 2 Description"
    }, 
    {
        "30" : ["Free", "Monthly", "Quaterly"]
    }, 
    {
        "40" : ["Day", "Swing"]
    }
],
}

I need to, in as few statements as possible, to achieve the following:

  1. Given a document like so:

    {"feature_id" : "30", "value" : ["Free"]}
    

    get the corresponding element of the array "features" to contain ["Free"] instead of ["Free", "Monthly", "Quaterly"]

  2. Given a document like so:

    {"feature_id" : "50", "value" : ["Bonds", "Commodities"]}
    

    create a new element of the array "features" looking like

    {"50" : ["Bonds", "Commodities"]}
    
  3. Given a document like so:

    {"feature_id" : "40", "value" : ""} 
    

remove the corresponding element from the array "features".

Was it helpful?

Solution

Data model

Your data model isn't easy to work with given your desired updates.

If you want to use an array, I would suggest changing the document structure to look like:

{
    "entity_id" : 10,
    "features" : [
        {
            feature_id: "10",
            value : "Test System 2"
        },
        {
            feature_id: "20",
            value: "System 2 Description"
        }, 
        {
            feature_id: "30",
            value: ["Free", "Monthly", "Quaterly"]
        }, 
        {
            feature_id: "40",
            value: ["Day", "Swing"]
        }
    ],
}

Alternatively, you could model as an embedded document:

{
    "entity_id" : 10,
    "features" : {
        "10" : "Test System 2",
        "20" : "System 2 Description",
        "30" : ["Free", "Monthly", "Quaterly"],
        "40" : ["Day", "Swing"]
    }
}

The benefit of modeling as an array is that you can add a multikey index across all features/values.

If you model as an embedded document, you could reference fields directly (i.e. features.10). This assumes you know what the keys are going to be, and you would have to index each feature value separately.

I'll assume the first format for the examples below. Also note that your key values have to match in type (so string "10" will not match number 10).

Example 1

Given a document like so:

{"feature_id" : "30", "value" : ["Free"]} get the corresponding element of the array "features" to contain ["Free"] instead of ["Free", "Monthly", "Quaterly"]

Sample update:

db.docs.update(
    // Criteria (assumes entity_id is unique)
    {
        entity_id: 10,
        features: {
            // Using $elemMatch to find feature_id with string "30"
            $elemMatch: { feature_id: "30" },
        }
    },

    // Update
    { $set: {
        "features.$.value" : ["Free"]
    }}
)

Example 2

Given a document like so:

{"feature_id" : "50", "value" : ["Bonds", "Commodities"]} create a new element of the array "features" looking like

{"50" : ["Bonds", "Commodities"]}

Sample update:

db.docs.update(
    // Criteria (assumes entity_id is unique)
    {
        entity_id: 10,
    },

    // Update
    { $push: {
        "features" : { "feature_id" : "50", value: ["Bonds", "Commodities"] }
    }}
)

Example 3

Given a document like so:

{"feature_id" : "40", "value" : ""}

remove the corresponding element from the array "features".

Sample update:

db.docs.update(
    // Criteria (assumes entity_id is unique)
    {
        entity_id: 10,
    },

    // Update
    { $pull: {
        "features" : { "feature_id" : "40" }
    }}
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top