user514005
user514005

Reputation:

Mongodb save/upsert using C# drivers, continuous array adds and field updates to same doc

I need some ideas/tips for this. Here is a sample document I am storing:

{
    "_id" : new BinData(0, "C3hBhRCZ5ZFizqbO1hxwrA=="),
    "gId" : 237,
    "name" : "WEATHER STATION",
    "mId" : 341457,
    "MAC" : "00:00:00:00:00:01",
    "dt" : new Date("Fri, 24 Feb 2012 13:59:02 GMT -05:00"),
    "hw" : [{
        "tag" : "Weather Sensors",
        "snrs" : [{
          "_id" : NumberLong(7),
          "sdn" : "Wind Speed"
        }, {
          "_id" : NumberLong(24),
          "sdn" : "Wind Gust"
        }, {
          "_id" : NumberLong(28),
          "sdn" : "Wind Direction"
        }, {
          "_id" : NumberLong(31),
          "sdn" : "Rainfall Amount"
        }, {
          "_id" : NumberLong(33),
          "sdn" : "Rainfall Peak Amount"
        }, {
          "_id" : NumberLong(38),
          "sdn" : "Barometric Pressure"
        }],
      "_id" : 1
    }]
}

What I am currently doing is using the C# driver and performing a .Save() to my collection to get upsert, however, what I want is kinda a hybrid approach I guess. Here are the distinct operations I need to be able to perform:

  1. Upsert entire document if it does not exist
  2. Update the dt field with a new timestamp if the document does exist
  3. For the hw field, I need several things here. If hw._id exists, update its tag field as well as handling the snrs field by either updating existing entries so the sdn value is updated or adding entirely new entires when _id does not exist

Nothing should ever be removed from the hw array and nothing should ever be removed from the snrs array.

A standard upsert does not appear to get me what I am after, so I am looking for the best way to do what I need with as few roundtrips to the server as possible. I am thinking some of the $ Operators may be what I am needing here, but just need some thoughts on how best to approach this.

The gist of what I am doing here is keeping an accumulating, historical document of snrs entries with the immediate current value as well as retaining any historical entries in the array even though they are no longer "alive", being reported, etc. This allows future reporting on things that no longer exist in current time, but were at some point in the past. _id values are application-generated, globally unique across all documents, and never change after initial creation. For example, last week "Wind Speed" was being reported, but this week it is not. It's _id value, however, will not change if "Wind Speed" starts reporting again. Follow?

Clarifications or more detail can be provided if needed.

Thanks.

Upvotes: 1

Views: 583

Answers (1)

Sridhar Nanjundeswaran
Sridhar Nanjundeswaran

Reputation: 754

By changing the structure of your document from embedded arrays to subdocuments key'ed by the _ids you can do this. e.g. { "MAC" : "00:00:00:00:00:01", "_id" : 1, "dt" : ISODate("2012-02-24T18:59:02Z"), "gId" : 237, "hw" : { "1" : { "snrs" : { "1" : "Wind Speed", "2" : "Wind Gust" }, "tag" : "Weather Sensors" } }, "mId" : 341457, "name" : "WEATHER STATION 1" }

I created the above document by the following upsert

db.foo.update(
{_id:1},
{
    $set: {
        "gId" : 237,
        "name" : "WEATHER STATION 1",
        "mId" : 341457,
        "MAC" : "00:00:00:00:00:01",
        "dt" : new Date("Fri, 24 Feb 2012 13:59:02 GMT -05:00"),
        "hw.1.tag" : "Weather Sensors",
        "hw.1.snrs.1" : "Wind Speed",
        "hw.1.snrs.2" : "Wind Gust"
    }
},
true
)

Now when I run

db.foo.update(
{_id:1},
{
    $set: {
        "dt" : new Date(),
        "hw.2.snrs.1" : "Rainfall Amount"
    }
},
true
)

I get

{
    "MAC" : "00:00:00:00:00:01",
    "_id" : 1,
    "dt" : ISODate("2012-03-07T05:14:31.881Z"),
    "gId" : 237,
    "hw" : {
            "1" : {
                    "snrs" : {
                            "1" : "Wind Speed",
                            "2" : "Wind Gust"
                    },
                    "tag" : "Weather Sensors"
            },
            "2" : {
                    "snrs" : {
                            "1" : "Rainfall Amount"
                    }
            }
    },
    "mId" : 341457,
    "name" : "WEATHER STATION 1"
}

Upvotes: 2

Related Questions