2

I have this structure:

public class User
{
    public ObjectId Id { get; set; }
    public Location Location { get; set; }
    public DateTime LastAround {get;set;}
}

public class Location
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

I've tried a few things but I want to update User's Location and when they were last around.

Tried this:

userHelper.Collection.Update(
    Query.EQ("_id", userId),
    Update.SetWrapped<Location>("Location", new Location { Latitude = latitude, Longitude = longitude }).Set("LastAround", DateTime.UtcNow));

and this:

userHelper.Collection.Update(
    Query.EQ("_id", userId),
    Update.Set("Location.Latitude", latitude)
        .Set("Location.Longitude", longitude)
        .Set("LastAround", DateTime.UtcNow));

Nothing worked...how can I do this?

Update 4/17:

userHelper.Collection.Update(
                Query.EQ("_id", new ObjectId(userId)),
                Update
                    .SetWrapped<Location>("Location", new Location { Longitude = longitude, Latitude = latitude })
                    .Set("LastAround", DateTime.UtcNow)
            );

The lng and lat value orders seem to be very important when doing queries on them. I was doing a geonear query and getting an strange out of bounds error. If you update in the wrong order it will put lats first and then you get the error.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
rball
  • 6,925
  • 7
  • 49
  • 77

3 Answers3

2

Both of your original Update statements should work. I wrote a small sample program to demonstrate.

After executing this Insert statement:

var userId = ObjectId.GenerateNewId();
var user = new User
{
    Id = userId,
    Location = new Location { Latitude = 1.0, Longitude = 2.0 },
    LastAround = new DateTime(2012, 4, 14, 0, 0, 0, DateTimeKind.Utc)
};
collection.Insert(user);

The document looks like this in the mongo shell:

> db.test.find()
{ "_id" : ObjectId("4f8c5d33e447ad34b8c7ac84"), "Location" : { "Latitude" : 1, "Longitude" : 2 }, "LastAround" : ISODate("2012-04-14T00:00:00Z") }
>

After executing the first form of the Update statement:

collection.Update(
    Query.EQ("_id", userId),
    Update
        .SetWrapped<Location>("Location", new Location { Latitude = 3.0, Longitude = 4.0 })
        .Set("LastAround", new DateTime(2012, 4, 15, 0, 0, 0, DateTimeKind.Utc)));

the document looks like this:

> db.test.find()
{ "_id" : ObjectId("4f8c5d33e447ad34b8c7ac84"), "Location" : { "Latitude" : 3, "Longitude" : 4 }, "LastAround" : ISODate("2012-04-15T00:00:00Z") }
>

And after executing the second form of the Update statement:

collection.Update(
    Query.EQ("_id", userId),
    Update
        .Set("Location.Latitude", 5.0)
        .Set("Location.Longitude", 6.0)
        .Set("LastAround", new DateTime(2012, 4, 16, 0, 0, 0, DateTimeKind.Utc)));

the document looks like this:

> db.test.find()
{ "_id" : ObjectId("4f8c5d33e447ad34b8c7ac84"), "Location" : { "Latitude" : 5, "Longitude" : 6 }, "LastAround" : ISODate("2012-04-16T00:00:00Z") }
>

So the two forms of the Update statement are working.

The full program is here:

http://www.pastie.org/3799469

Robert Stam
  • 12,039
  • 2
  • 39
  • 36
  • Strange, I have no idea why mine wasn't working. I have learned since though the for geo queries the lat and lng need to switch positions with the lng being first. – rball Apr 17 '12 at 21:16
0

Both of your alternatives look ok.

Are you sure that your userId variable had the correct value? It could be that the Update is not finding a matching document to update.

Robert Stam
  • 12,039
  • 2
  • 39
  • 36
  • Yeah, everything looked ok. Couldn't get the update statement to work though. – rball Apr 16 '12 at 17:35
  • If your userId variable was of type string and you weren't converting it to an ObjectId in the call to Query.EQ then Find would not have found the matching document (because a string can't equal an ObjectId). So it seems likely that your Update wasn't doing the update because the query wasn't matching any document. – Robert Stam Apr 16 '12 at 18:04
  • That could be it, let me look again and try. userId is a string so that's entirely likely. I think I did var id = new ObjectId(userId) other places so I'll give that a whirl. Thanks for the help. – rball Apr 17 '12 at 21:18
0

What I ended up doing:

var userHelper = new MongoHelper<User>();
ObjectId id = new ObjectId(userId);
var user = userHelper.Collection.FindAll().Where(u => u.Id == id).Single();
user.LastAround = DateTime.UtcNow;
user.Location = new Location { Longitude = longitude, Latitude = latitude };
userHelper.Collection.Save(user);

which works. Not sure why the other way wouldn't. I suppose this is more "SQL" like although might not have the best performance. :(

rball
  • 6,925
  • 7
  • 49
  • 77
  • There is a problem with this code, because FindAll is returning *all* the documents from the server, and then you are using a client-side Where to find the one you want to update. See the new answer I started with sample code. – Robert Stam Apr 16 '12 at 18:03
  • The FindAll isn't IQueryable? How would I properly do this command then in other cases? In either case, I'll try switching it when I get home tonight. I didn't see your replies till today. – rball Apr 17 '12 at 21:19
  • FindAll is IEnumerable, so the Where clause is executed client side. You can create a query using Query.EQ("_id", id) and pass it as an argument to Find. Or you can call collection.AsQueryable().Where(u => u.Id = id) to use LINQ to MongoDB. – Robert Stam Apr 18 '12 at 01:33