How can I update a inner property using the 10gen c# driver? - mongodb

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.

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

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.

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. :(

Related

Swift Firebase RealtimeDatabase doesn't give child specific data with tons of data

In my project I used to have more than 6.000 points of interest (pois). Now I need to access for example the title of one poi with specific ID. Normally it works fine in my app when I need some specific from user for example.
I do the same steps like I usually do. But when I try to access poi data, it only give the whole "poi" data (>6.000 pois). I tried getData even observeSingeEvent.
This is my database structure:
{
"pois" : {
"0015CF32-D5B2-481A-8DA2-877E621A4E82" : {
city = a,
"country" = a,
creator = System,
id = "0015CF32-D5B2-481A-8DA2-877E621A4E82",
latitude = "1",
longitude = "1",
street = "a",
title = "a",
type = 0,
zip = 1
}, + 6.000 more...
"users" : {
"6EA555FA-BAA8-4EDE-BD05-5D290B953CAC" : {
"City" : "Motown",
"Country" : "Anywhere",
"Forename" : "Fred",
"Surename" : "Feuerstein",
"onTour" : "false",
"registeredEmail" : "fred#feuerstein.com",
"userId" : "6EA555FA-BAA8-4EDE-BD05-5D290B953CAC",
"userImagePath" : "6EA555FA-BAA8-4EDE-BD05-5D290B953CAC.jpg",
"username" : "Tom"
}
}
}
My request and result for user data: (I reduced the whole code because it doesn't matter what happens within the completion)
database.child("users/6EA555FA-BAA8-4EDE-BD05-5D290B953CAC/registeredEmail").getData { error, snap in
print(snap)
}
results: Snap (registeredEmail) fred#feuerstein.com
My request and result for user data.
database.child("pois/42E11715-B3B0-46D9-A568-E578870EF9A4/title/").getData { error, snap in
print(snap)
}
results (Shorten):
Snap (title) {
"0015CF32-D5B2-481A-8DA2-877E621A4E82" = {
city = a;
"country" = a;
creator = System;
id = "0015CF32-D5B2-481A-8DA2-877E621A4E82";
latitude = "1";
longitude = "1";
street = "a";
title = "a";
type = 0;
zip = 1;
};
"002A3A1C-DE5C-4CB4-AD36-1B4495B77F22" = {
city = "b";
"country" = b;
creator = System;
id = "002A3A1C-DE5C-4CB4-AD36-1B4495B77F22";
latitude = "1";
longitude = "1";
rating = 0;
street = "b";
title = "b";
type = 0;
zip = 1;
}; + 6.000 more pois
I guess this coherent with the amount of data in "pois". Someone an idea how to solve the problem?

How to get MongoDB entries in date range including limits?

In a Mongo DB, I have the below entries:
> db.DomainObjects.find()
// [...]
{ "_id" : ObjectId("6..3"), "lev" : 7, "date" : ISODate("2021-02-01T00:00:00Z"), "val" : 29.1 }
{ "_id" : ObjectId("6..4"), "lev" : 7, "date" : ISODate("2021-02-02T00:00:00Z"), "val" : 20.3 }
{ "_id" : ObjectId("6..5"), "lev" : 7, "date" : ISODate("2021-02-05T00:00:00Z"), "val" : 15.8 }
// [...]
In a ASP.NET Core Service class, I have a reference to the collection using the Mongo DB driver with the below version installed:
Here is how the reference is created:
public DomainService(IDomainDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_repo = database.GetCollection<Domain>(settings.DomainCollectionName);
}
Then I'd like to get the entries by DateTime range (including the limits) using the following method:
public List<Domain> Get(int lev, DateTime dateFrom, DateTime dateTo) {
Expression<Func<Domain, bool>> expr = entry => (entry.lev == lev) &&
(entry.date.CompareTo(dateFrom) >= 0) &&
(entry.date.CompareTo(dateTo) <= 0);
return _repo.Find(expr).ToList();
I use the following GET request:
https://localhost:45645/api/DomainObjects/7/?dateFrom=2021-02-01&dateTo=2021-02-02
However, I only get the entries starting and including the lower limit, the entry on the upper limit is excluded.
For completeness, the controller is this:
[HttpGet("{lev:int}")]
public ActionResult<List<Domain>> Get(int lev, [FromQuery] DateTime? dateFrom = null, [FromQuery] DateTime? dateTo = null) {
if (!dateFrom.HasValue) {
dateFrom = DateTime.MinValue;
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
if (!dateTo.HasValue) {
dateTo = DateTime.Today;
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
If the lower limit dateFrom is omitted in the request, it should start with the earliest entry, if the limit dateTo is omitted, it should return all values from dateFrom up until and including today.

How to do OR inside of AND?

SQL query=>
where and ((subtype="dailyMessage" and registDate="today") or(subtype !="dailyMessage"))
i want to retrive this query by using mongodb.
i have this collection. (today is '2017-08-16T15:48:19.947Z')
{
"_id" : ObjectId("597768443b1fd6308c0350c0"),
"type" : "message",
"subtype" : "dailyMessage",
"message" : test1",
"registDate" : ISODate("2017-08-16T15:48:19.947Z")
},
{
"_id" : ObjectId("597768443b1fd6308c0350c1"),
"type" : "message",
"subtype" : "dailyPush",
"message" : test2",
"registDate" : ISODate("2017-07-25T15:48:19.947Z")
},
{
"_id" : ObjectId("597768443b1fd6308c0350c2"),
"type" : "message",
"subtype" : "dailyPush",
"message" : test3",
"registDate" : ISODate("2017-07-24T15:48:19.947Z")
}
here is my code(spring boot mongodb , using java 8)
List<String> listOfmessage = new ArrayList<String>();
listOfSubtype.add("dailyMessage");
criteria = Criteria.where("test").is("james");
criteria.andOperator(Criteria.where("registDate").gte(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT)).lte(LocalDateTime.now()) , Criteria.where("subtype").in(listOfmessage) .orOperator(Criteria.where("subtype").nin(listOfmessage)));
my problem is that how can i insert orOperator on the andOperator?
As mentioned in the comment, the and outside the whole condition doesn't make sense. The below code is written for the following condition.
(condition1 AND condition2) OR condition3
Code:-
You may need to alter the below code to get the MongoOperations object based on your Spring configuration.
"register" is the collection name. You can change it accordingly as per your collection name.
public Boolean getRegisterData() {
MongoOperations mongoOperations = getMongoConnection();
List<String> listOfSubType = new ArrayList<String>();
listOfSubType.add("dailyMessage");
List<String> listOfMessage = new ArrayList<String>();
listOfMessage.add("test1");
Criteria criteriaSubTypeAndDate = new Criteria();
criteriaSubTypeAndDate.andOperator(Criteria.where("registDate")
.gte(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT)).lte(LocalDateTime.now()),
Criteria.where("subtype").in(listOfSubType));
Criteria criteriaSubType = Criteria.where("subtype").ne("dailyMessage");
Criteria criteriaFull = new Criteria();
criteriaFull.orOperator(criteriaSubTypeAndDate, criteriaSubType);
Query query = new Query();
query.addCriteria(criteriaFull);
System.out.println(query);
mongoOperations.executeQuery(query, "register", new RegistryDocumentCallbackHandler());
return true;
}
Result set document processing class:-
processDocument() method will get executed for each document in the result set.
public class RegistryDocumentCallbackHandler implements DocumentCallbackHandler {
#Override
public void processDocument(DBObject dbObject) throws MongoException, DataAccessException {
System.out.println("Registry collections data ===>" + dbObject.toString());
}
}

Spring data mongo aggregation mapping to object

I want to map the results of an aggregation to an POJO without iterating through the raw results. The POJO is a field in the Collection on which I'm running the aggregation.
MatchOperation match = match(Criteria.where("drill").is(drill));
SortOperation sort = sort(DESC, "creationDate");
GroupOperation group = group("athlete").first("athlete").as("athlete");
LimitOperation limit = limit(10);
ProjectionOperation project = project("athlete");
Aggregation aggregation = newAggregation(match, sort, group, limit, project);
AggregationResults<Athlete> results = mongoTemplate.aggregate(aggregation, DrillResultInfo.class, Athlete.class);
List<Athlete> mappedResult = results.getMappedResults();
It returns the correct number of objects, but they have as the id the map of the object and the other properties are null.
The result:
id: { "_id" : { "$oid" : "57cd46780348276373579821"} , "_class" : "Athlete" , "firstName" : "Jenny" , "lastName" : "Smith" ....}
The rest of the properties are null.
The Collection:
public class DrillResultInfo {
#Id
private String id;
private Long resultId;
#DBRef
private Athlete athlete;
#DBRef
private Drill drill;
....
}
(.... represents left out data)
Update:
I've made some updates to the code to get it to work:
List<Athlete> respone = new ArrayList<>();
MatchOperation match = match(Criteria.where("drill").is(drill));
SortOperation sort = sort(DESC, "creationDate");
GroupOperation group = group("athlete");
LimitOperation limit = limit(5);
SkipOperation skip = skip(skipElements);
ProjectionOperation project = project("_id");
TypedAggregation<DrillResultInfo> agg = newAggregation(DrillResultInfo.class, match, sort, group, skip, limit, project);
AggregationResults<Object> results = mongoTemplate.aggregate(agg, Object.class);
List<Object> mappedResult = results.getMappedResults();
for (Object obj : mappedResult) {
Athlete ath = (Athlete) ((LinkedHashMap) obj).get("_id");
respone.add(ath);
}
return respone;
I would like to get rid of that for.

How to query/update sub document in MongoDB using C# driver

public class DayData
{
public string _id
{get;set;}
public string Data
{get;set;}
public HourData HR1
{get;set;}
public HourData HR2
{get;set;}
...
public HourData HR24
{get;set;}
}
public class HourData
{
public long _id
{get;set;}
public int Count
{get;set;}
public string Data
{get;set;}
}
// Sample Data
{
"_id": "2012_11_10",
"Data": "some data",
"HR1":
{
"_id": 1
"Count": 100,
"Data": "Hour 1 Data"
},
"HR2":
{
"_id": 2
"Count": 200,
"Data": "Hour 2 Data"
},
...
"HR24":
{
"_id": 24
"Count": 2400,
"Data": "Hour 24 Data"
}
}
I have following questions (by using C# official driver):
How to retrieve single HourData document from DayData collection (using single database query)? e.g. I need to retrieve HourData document of HR1 for DayData (where _id="2012_11_10"). Please refer to code snippet i tried as Edit-1.
How to update/upsert HourData document to increment its Count (using single database operation, like: collection.update(Query, Update))? e.g. I need to increment Count of HR1 for DayData (where _id="2012_11_10").
How to retrieve Sum of all Count values of HR1, HR2,...,HR24 for DayData (where _id="2012_11_10") (using some aggregate function).
What is the best way to convert the HourData Counts of all hours to an array (for any DayData). e.g. for a DayData with _id="2012_11_10", i need:
int []Counts = [100,200,300, ... , 2400]
Edit-1
With this code I intend to get HourData of HR1 where its _id=1 and DayData with _id="2012_11_10", but it does not return anything.
MongoCollection<HourData> dayInfo = mdb.GetCollection<HourData>("HourData");
var query = Query.And(Query.EQ("_id", "2012_11_10"), Query.EQ("HR1._id", 1));
MongoCursor<HourData> hri = dayInfo.Find(query);'
1)
QueryComplete = Query.EQ(_id, "2012_11_10");
DayData myData = db.GetCollection<DayData>("DayDataCollection").FindOne(query);
// As HourData is the class member you can retrieve it from the instance of the DayData:
HourData myHour = myData.HR1;
2)
QueryComplete = Query.EQ(_id, "2012_11_10");
UpdateBuilder update = Update.Inc("HR1.Count", 1);
db.GetCollection<DayData>("DayDataCollection").Update(query, update, SafeMode.True)
;
3)
In your case you just retrieve the DayData instance and then sum all needed values explicitly:
QueryComplete = Query.EQ(_id, "2012_11_10");
DayData myData = db.GetCollection<DayData>("DayDataCollection").FindOne(query);
// As HourData is the class member you can retrieve it from the instance of the DayData:
int sum = myData.HR1.Count + myData.HR2.Count + ... + myData.HR24.Count;
But it's not elegant. If you want the elegant solution you need to transform your fields into the array like:
DayData
{
HR:
[{
Count: 1,
Data: "Hour 1 data"
},
{
},
...
]
}
and work as with the array. Let me know if it's possible to transform it into an array.
4)
In your case, again, there is no any elegant solution. What you can do just go through your fields and create an array:
int[] Counts = new int[24];
Counts[0] = myData.HR1.Count;
...
Or you can create enumerator right in the class but I think it's overkill in your case.