public class Student
{
public long StudentId {get; set;}
public string Fname {get; set;}
public string Lname {get; set;}
public List<ObjectId> CoursesList {get; set;}
public int IQ {get;set;}
}
public class Courses
{
[BsonId]
public ObjectId Id { get; set; }
public string CourseNumber{get; set;}
public string CourseName{get; set;}
}
How do I add/append a courser Id to Course list(which may be null for the first time) of a Student object
PS: I know how to set a field using the below command. I am hoping it is on similar lines for the above problem
await StudentCollection.UpdateOneAsync(a => a.StudentId == studentId, Builders<Student>.Update.Set( a => a.IQ,90));
As you've already discovered, the C# code to use $addToSet is:
var filter = Builders<Student>.Filter.Eq(s => s.StudentId, studentId);
var update = Builders<Student>.Update.AddToSet(s => s.CoursesList, courseId);
var result = await collection.UpdateOneAsync(filter, update);
However, $addToSet is not going to work if the CourseList member has been stored in the collection as a null. The server requires that the existing value for $addToSet be an array (it can be an empty array).
The easiest solution is to just store an empty list for CoursesList instead of a null when there are no courses.
This is working for me. When you define "List" like this, it will be empty and works with AddToSet/Push methods.
public List<ObjectId> CoursesList = new List<ObjectId>();
The only case that you have to pay attention is when the array CourseList is null, in this case you have to use the code below (see also here):
var newListOfObject = new List<ObjectId>(){...}
await StudentCollection.UpdateOneAsync(a => a.StudentId == studentId, Builders<Student>.Update.Set( a => a.CoursesList, newListOfObject));
Otherwise you can use AddToSet or Push like explain in the other answers.
Related
I have a class:
public class FlightDetails
{
public string FlightId {get; set;}
public string PilotName {get; set;}
public string Area {get; set;}
public string Country {get; set;}
}
Here sending response:
public async Task<List<FlightDetails>> GetFlightAsync(string FlightId)
{
//
var flights = new List<FlightDetails>();
flights = response.AllFlights;
flights = flights.Where(x => x.FlightId.Contains(FlightId)).ToList();
//
return flights;
}
Getting List here and data is filled but issue is don't want FlightId and Country in the response which I am sending. How to remove this objects in the List? Finally in the List item there should be only PilotName and Area.
Update:
I forgot the following line before the flights = response.AllFlights;
var request = await _rest.Get<WorldFlights>(url + $"?FlightId={FlightId}");
You will need to create another object, and map there only the properties you want. For example:
public class FlightDetailsResponse
{
public string PilotName {get; set;}
public string Area {get; set;}
}
And then in the function:
public async Task<List<FlightDetailsResponse>> GetFlightAsync(string FlightId){
var flights = response.AllFlights;
var flightResponses = flights
.Where(x => x.FlightId.Contains(FlightId).ToList())
.Select(x => new FlightDetailsResponse{
PilotName = x.PilotName,
Area = x.Area
});
return flightResponses;
}
This way the response will only contain the PilotName and Area fields.
PD: What I wrote might not compile because of missing commas or something like that. Sorry, it has been some time since I last wrote C#, but the idea is that.
I have a Collection Students which Stores registered students data in MongoDB. It has StudentName, SaveDate etc. fields. I am displaying the details to my website from my .net framework WebAPI.
What I want to do is Get StudentDetails with prev next student ID's by the order of SaveDate.
My current query gets Student details by student id from below query,
var collection = StudentDB.Collection<Student>("StudyMaterials");
var curfilter = Builders<Student>.Filter.Eq(x => x.studentID, studentID);
studentDetails= collection.Find(curfilter).FirstOrDefault();
This is my Student.cs class,
public class Student
{
[BsonRepresentation(BsonType.String)]
public Guid StudentID {get; set;}
public string StudentName {get; set;}
[BsonRepresentation(BsonType.String)]
public Guid NextStudentID {get; set;}
[BsonRepresentation(BsonType.String)]
public Guid PrevStudentID {get; set;}
}
I want to use aggregation but don't know how to sort by multiple sort definitions on the aggregation framework.
First of all, I don't think you need to keep the students like that. I suggest the following:
public class Student
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public DateTime SaveDate { get; set; }
}
You need to make sure that the documents are sorted by SaveDate. For instance, when inserting new students into the database you can do it like this:
var student = new Student
{
Name = "Sara",
SaveDate = DateTime.UtcNow
};
context.Students.InsertOne(student);
Now, you can get the documents with Skip and Limit:
var skip = 0;
var limit = 1;
var context = new MongoContext();
var filter = Builders<Student>.Filter.Empty;
var result = context.Students.Find(filter).Skip(skip).Limit(limit).FirstOrDefault();
Increment skip to get next and so on.
I have following classes:
public class QualifyResponse
{
public Message[] MessageList{get; set;}
}
public class Message
{
public MessageDetail[] MessageDetailList{get; set;}
public string MessageStatus{get; set;}
public string ProviderCode{get; set;}
}
public partial class MessageDetail
{
public string MessageCategory{get; set;}
public string MessageCode{get; set;}
public string MessageSeverity{get; set;}
public string MessageText{get; set;}
}
What I want is, For all the MessageDetailList, if the messageCode is equal to "status" then assign its messageText value to "Complete" after this query
I tried the following LINQ, but it didnt work i.e the MessageDetailList objects having MessageCode = "status" didn't have MessageText = "Complete".
response.MessageList.FirstOrDefault()
.MessageDetailList
.Where(message => message.MessageCode
.ToLower()
.Equals("status"))
.ToList()
.ForEach(status =>
{
status.MessageText = "Complete";
});
What am I doing wrong?
A bit of formatting helps read your code
However this should help and double check the results
Note if your Where clause is correct it WILL update your
MessageText providing there isn't some funky setter going on
var message = response.MessageList.FirstOrDefault();
var messageDetails = message.MessageDetailList
.Where(message => message.MessageCode.ToLower() == "status")
.ToList();
messageDetails.ForEach(status => status.MessageText = "Complete");
messageDetails.ForEach(status => Debug.WriteLine(status.MessageText));
Update
This all should work fine
Try a foreach instead
Try putting a try catch around it all
Try checking the result immediately after you are setting it.
If this from Ef try `SaveChanges'
We don't know how you are checking your results
I have the following classes:
class Customer
{
public int IdCustomer {get; set}
public string Name {get; set;}
public virtual ICollection<Expertise> Expertises {get; set;}
}
class Expertise
{
public int IdExpertise {get; set;}
public string Description {get; set;}
public virtual ICollection<SubExpertise> SubExpertises {get; set;}
}
class SubExpertise
{
public int IdSubExpertise { get; set;}
public int IdExpertise {get; set;}
public string Description {get; set;}
public virtual Expertise Expertise {get; set;}
}
How I can filter a SubExpertise using a IQueryable, and keep the filter condition? Basically I want to filter by SubExpertise, but keeping the possibilty to add more filters in the query
Example: I wanna all customers that have a SubExpertise 'x' or 'y'. Keep in mind that SubExpertise is a sub-collection of a collection (Expertise). And that I can have new filters after this.
I think you're after a method to build the expressions dynamically. You could use a predicate builder to do the job. My favorite is this one.
Using this little gem you can do this:
var pred = PredicateBuilder.Create<SubExpertise>(s => s.Description == "x");
pred = pred.Or(s => s.Description == "y");
var customers = db.Customers
.Where(c => c.Expertises
.Any(e => e.SubExpertises.AsQueryable()
.Any(pred)));
e.SubExpertises must be cast to IQueryable because it's compile-time type is ICollection, and the extension method Any that fits ICollection doesn't accept an Expression but a Func, so it doesn't compile.
I use a pattern like this for resuable filters, defining the filters as Expressions
public static class SubExpertiseFilter
{
public static Expression<SubExpertise, bool> XorY =
se => se.Description == "X" || se.Description == "Y";
}
Then if I want to apply it:
public IQueryable<Expertise> ApplyXorYFilter(IQueryable<Expertise> expertises, bool appyXorY)
{
if(applyXorY)
{
expertises = expertises.Any(e => e.Subexpertises.AsQueryable().Any(SubExpertiseFilter.XorY);
}
return expertises;
}
Or just do it inline where you need it.
The "AsQueryable" is needed to use the expression inside another expression so that EF is happy with it, otherwise the compiler expects a function there and that isn't something EF can turn into SQL.
Suppose you have a list customers
var filteredCustomers = from customer in customers
where customer.Expertises.Any(e => e.Subexpertises.Any(s => IsXOrY(s)))
select customer;
You can add any filter conditions in IsXOrY: (and you should rename it)
bool IsXOrY(SubExpertise subExpertise)
{
check if the SubExpertise is 'x' or 'y'
check if the SubExpertise meets other criteria
return true if this SubExpertise meets all your criteria
}
I have a rich NHibernate dbo object that I need to query to extract a keyword and related array of country codes.
To explain:
I have 3 related DBO objects returned from a database, that have the following structure:
class DboCountry{
public int CountryId {get;set;}
public string CountryCode {get;set;}
}
class DboPage{
public int Id {get;set;}
public string Keyword {get;set;}
}
class DboPageCountry{
public int Id {get;set;}
public DboThemePage DboThemePage {get;set;}
public DboCountry DboCountry {get;set;}
}
As such when querying the database I get a List of DboPageCountries that contain multiple repeating DboPage.Keyword that are associated to various DboCountry.CountryCode
What I need to do is take the List of DboPageCountries and create an array of DtoKeywordCountryCode with the following structure:
class DtoKeywordCountryCode{
public string Keyword {get; set;}
public string[] CountryCodes {get; set;}
}
So far, using Linq, I've either been able to group the keywords, but not get the associated country codes, or get keywords and country codes, but not associated as a unique Keyword against an array of applicable CountryCodes.
Any pointers in the right direction much appreciated.
Try this -
var items = new List<DboPageCountry>(); //list of DboPageCountries
var items2 = from x in items.GroupBy(x => x.DboThemePage)
select new DtoKeywordCountryCode { Keyword = x.First().DboThemePage.Keyword, CountryCodes = x.Select(c => c.DboCountry.CountryCode).ToArray() };
DtoThemePage[] dtoThemePageArrayFull = (from tpc in dboThemePageCountryList group tpc by tpc.DboThemePage.Keyword into k
select new DtoThemePage
{
Keyword = k.Key,
CountryCodes = k.Select(c => c.DboCountry.CountryCode).ToArray<string>()
}).ToArray<DtoThemePage>();