Reputation: 2245
I am not sure if the title match what I am looking for, but here it is: I have a json that looks like this:
[
{
"Class" : "Math",
"Location" : "South Hall",
"Professor" : "Donald Duck"
"Student":
[
{
"FirstName" : "John",
"LastName" : "Doh",
"DOB" : "1990",
"SS": "123456789"
},
{
"FirstName" : "Jane",
"LastName" : "Smith",
"DOB" : "1990",
"SS": "023456789"
},
{
"FirstName" : "John",
"LastName" : "Smith",
"DOB" : "1995",
"SS": "003456789"
}
]
}
]
I want to be able to read the document using student First and Last name, but I want to only return the array item for this student along with the rest of the json, and exclude the rest of the students, so for example, say my query is:
db.Class.find({"Student.FirstName" : "Jane", "Student.LastName" : Smith"})
I want my return json to look like this:
[
{
"Class" : "Math",
"Location" : "South Hall",
"Professor" : "Donald Duck"
"Student":
{
"FirstName" : "Jane",
"LastName" : "Smith",
"DOB" : "1990",
"SS": "023456789"
}
}
]
Any ideas how to do that ? I am using the C# driver and my poco looks like this:
public class Rootobject
{
public string Class { get; set; }
public string Location { get; set; }
public string Professor { get; set; }
public Student Student { get; set; }
}
public class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string DOB { get; set; }
public string SS { get; set; }
}
Upvotes: 0
Views: 1385
Reputation: 9679
First of all your POCO classes are wrong. You don't have a single student on your rootobject, but a colelction of students.
public class Rootobject
{
public int Id { get; set;}
public string Class { get; set; }
public string Location { get; set; }
public string Professor { get; set; }
public Student[] Student { get; set; }
}
Here is a sample code to get what you want with c# MongoDb driver.
To load collection from db:
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("testdb");
var collection = db.GetCollection<Rootobject>("students");
To get data from mongo:
collection.Find(r => r.Student.Any(s => s.FirstName == "Jane" && s.LastName == "Smith"))
.Project(
Builders<Rootobject>.Projection.Include(x=>x.Class)
.Include(x=>x.Location)
.Include(x=>x.Professor)
.ElemMatch(x=> x.Student, y=>y.FirstName=="Jane" && y.LastName=="Smith"))
.ToEnumerable()
The problem you could have with results of this query is: you will get BSonDocument, not rootobject. Possible solution is to generate new instances of your rootobjects (use directly after ToEnumerable()
):
.ToEnumerable()
.Select(r => new Rootobject {
Class = r[nameof(Rootobject.Class)].AsString,
Location = r[nameof(Rootobject.Location)].AsString,
Professor = r[nameof(Rootobject.Professor)].AsString,
Student = r[nameof(Rootobject.Student)].AsBsonArray.Select(s => new Student
{
DOB = s[nameof(Student.DOB)].AsString,
FirstName = s[nameof(Student.FirstName)].AsString,
LastName = s[nameof(Student.LastName)].AsString,
SS = s[nameof(Student.SS)].AsString,
}).ToArray(),
})
Other possibility: You get your root objects with all students to client and filter your students already in results of the query:
var result = collection
.Find(r => r.Student
.Any(s => s.FirstName == "Jane" && s.LastName == "Smith")).ToEnumerable()
.Select(r =>
{
r.Student = r.Student.Where(s => s.FirstName == "Jane" && s.LastName == "Smith")
.ToArray();
return r;
})
Upvotes: 1
Reputation: 1957
Try the following aggregate:
db.collection.aggregate(
[
{ $unwind: "$Student" },
{ $match: {"Student.FirstName" : "John", "Student.LastName" : "Doh"}},
{ $unwind: "$Student" },
{ $project: { "Student" : 1 , "Professor" : 1, "Class" : 1, "Location" : 1, "_id" : 0}}
]
);
Output:
{
"Class" : "Math",
"Location" : "South Hall",
"Professor" : "Donald Duck",
"Student" : {
"FirstName" : "John",
"LastName" : "Doh",
"DOB" : "1990",
"SS" : "123456789"
}
}
Hope this helps.
Upvotes: 0