I'm trying to get an array of all points from reports so that they can be mapped. To do this I need an unwind/projection but I'm struggling to get my head around it.
The result is formatted like so..
"totalPoints": 200,
"points": [
{
"itemId": "5e9592edb4959a52b8493f6d",
"itemName": "Numquam hic minus repellat sequi.",
"name": null,
"longitude": null,
"latitude": null
},
...
As you can see I'm getting nulls for the bottom 3 items.
Here is the query I'm using
var points = await _reportDocs.Aggregate()
.Match(filter.GenerateFilter())
.Unwind<IntelReport, IntelReportLocationUnwound>(x => x.Locations)
.Project(x => new LocationDto
{
ItemId = x.Id,
ItemName = x.Name,
Name = x.Location.Name,
Latitude = x.Location.Point.Coordinates[1],
Longitude = x.Location.Point.Coordinates[0]
})
.ToListAsync();
Here is the original report class (but I've took some stuff out which wasn't needed here)
public class IntelReport
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string ReportTitle { get; set; }
public ICollection<Location> Locations { get; set; }
}
and the classes I thought I needed to do the unwind...
public class LocationDto
{
[BsonRepresentation(BsonType.ObjectId)]
public string ItemId { get; set; }
public string ItemName { get; set; }
public string Name { get; set; }
public double? Longitude { get; set; }
public double? Latitude { get; set; }
}
[BsonIgnoreExtraElements]
public class IntelReportLocationUnwound
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("ReportTitle")]
[BsonIgnoreIfDefault]
public string Name { get; set; }
[BsonElement("locations")]
[BsonIgnoreIfDefault]
public LocationForAgg Location { get; set; }
}
public class LocationForAgg
{
[BsonElement("name")]
[BsonIgnoreIfDefault]
public string Name { get; set; }
[BsonElement("point")]
[BsonIgnoreIfDefault]
public PointForAgg Point { get; set; }
}
public class PointForAgg
{
[BsonElement("coordinates")]
[BsonIgnoreIfDefault]
public double[] Coordinates { get; set; }
}
$unwind converts an array of subdocuments into a single subdocument so your data after .Unwind<IntelReport, IntelReportLocationUnwound>(x => x.Locations)
will look like this:
{
"_id" : ObjectId("5e968bd5cc41498362cee2d2"),
"ReportTitle" : "aa",
"Locations" : {
"ItemId" : ObjectId("5e968bd5cc41498362cee2d3"),
"ItemName" : "Name",
"Name" : "N",
"Longitude" : 15,
"Latitude" : -24
}
}
which means that you have to rethink the IntelReportLocationUnwound
class definition. You can use the same type you had in IntelReport
since MongoDB will only convert it from an array into a nested object:
public class IntelReportLocationUnwound
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("ReportTitle")]
[BsonIgnoreIfDefault]
public string Name { get; set; }
[BsonElement("Locations")]
[BsonIgnoreIfDefault]
public Location Location { get; set; }
}
then you can modify your aggregation:
.Project(x => new LocationDto
{
ItemId = x.Id,
ItemName = x.Name,
Name = x.Location.Name,
Latitude = x.Location.Latitude,
Longitude = x.Location.Longitude
})