How to get first 5 questions of list? - c#
I'm trying to create a quiz program but at the moment I have a list for each category. I would like to use the same list and just call the categories I want in each quiz.
private void LoadQuestions()
{
Question q1 = new Question
{
NameOfQuestion = "Vem är världens bästa golfspelare?",
Options = new List<string>() { "Tiger Woods", "Matt Kuchar", "S.H. Kim", "Adam Scott" },
Answer = "Tiger Woods",
Category = "Golf"
};
Question q2 = new Question
{
NameOfQuestion = "Vad heter Rory i efternamn?",
Options = new List<string>() { "Svensson", "Mcilroy", "Eriksson", "Smith" },
Answer = "Mcilroy",
Category = "Golf"
};
Question q3 = new Question
{
NameOfQuestion = "Hur många golfhål spelar man under en tävling?",
Options = new List<string>() { "18", "26", "72", "180" },
Answer = "72",
Category = "Golf"
};
Question q4 = new Question
{
NameOfQuestion = "Vilken bana spelas Masters på?",
Options = new List<string>() { "TPC Sawgrass", "Agusta", "Halmstad GK", "The Country Club" },
Answer = "Agusta",
Category = "Golf"
};
Question q5 = new Question
{
NameOfQuestion = "Vad har Gustav i HCP?",
Options = new List<string>() { "Alldeles för högt", "Alldeles för lågt", "Han är bäst", "Han är sämst" },
Answer = "Han är sämst",
Category = "Golf"
};
Question q6 = new Question
{
NameOfQuestion = "Hur många spelare är på isen samtidigt?",
Options = new List<string>() { "8", "10", "6", "12" },
Answer = "12",
Category = "Hockey"
};
Question q7 = new Question
{
NameOfQuestion = "Hur lång är en hockeymatch?",
Options = new List<string>() { "40 minuter", "60 minuter", "90 minuter", "45 minuter" },
Answer = "60 minuter",
Category = "Hockey"
};
Question q8 = new Question
{
NameOfQuestion = "Hur många poäng får ett lag om de vinner i övertid?",
Options = new List<string>() { "3", "4", "2", "1" },
Answer = "2",
Category = "Hockey"
};
Question q9 = new Question
{
NameOfQuestion = "Vilken färg har en hockeypuck?",
Options = new List<string>() { "Mörkblå", "Svart", "Grå", "Svart & vit" },
Answer = "Svart",
Category = "Hockey"
};
Question q10 = new Question
{
NameOfQuestion = "Vad kallas det när det står 40-40 i tennis?",
Options = new List<string>() { "Even", "All square", "Deuce", "Even Steven" },
Answer = "Deuce",
Category = "Tennis"
};
Question q11 = new Question
{
NameOfQuestion = "Vad heter den kända svensken som tog 11 grand slam-segrar?",
Options = new List<string>() { "Björn Borg", "Stefan Edberg", "Gustav Eriksson", "Mats Wilander" },
Answer = "Björn Borg",
Category = "Tennis"
};
Question q12 = new Question
{
NameOfQuestion = "Vart föddes den kända tennisspelaren Andy Murray?",
Options = new List<string>() { "Wales", "England", "Scotland", "Ireland" },
Answer = "Scotland",
Category = "Tennis"
};
Question q13 = new Question
{
NameOfQuestion = "Vad kallas det kända mästerskap som spelas i England varje år?",
Options = new List<string>() { "Wimbledon", "Offerthon", "English Tennis Cup", "London Tennis Championship" },
Answer = "Wimbledon",
Category = "Tennis"
};
Question q14 = new Question
{
NameOfQuestion = "Avsluta meningen: Game, Set & ",
Options = new List<string>() { "Victory", "Relax", "Time to make your bet", "Match" },
Answer = "Match",
Category = "Tennis"
};
Question q15 = new Question
{
NameOfQuestion = "Vilken låt är den mest strömmade på spotify?",
Options = new List<string>() { "The Weeknd - Blinding Lights", "Ed Sheeran - Shape Of You", "Tones And I - Dance Monkey", "Post Malone - Rockstar" },
Answer = "The Weeknd - Blinding Lights",
Category = "Music"
};
Question q16 = new Question
{
NameOfQuestion = "Vilket band har gjort låten: Smoke on the water?",
Options = new List<string>() { "Europe", "Iron Maiden", "Rolling Stones", "Deep Purple" },
Answer = "Deep Purple",
Category = "Music"
};
Question q17 = new Question
{
NameOfQuestion = "Vilken är Avicii's mest streamade låt på spotify?",
Options = new List<string>() { "The Nights", "The Days", "Wake Me Up", "Without you" },
Answer = "Wake Me Up",
Category = "Music"
};
Question q18 = new Question
{
NameOfQuestion = "The Beatles är otroligt känt band med bandmedlemmar som John Lennon, Ringo Starr och Paul McCartney. Vad heter den fjärde medlemmen?",
Options = new List<string>() { "George Harisson", "Dean Smith", "George Davidson", "Terry McDavid" },
Answer = "George Harisson",
Category = "Music"
};
Question q19 = new Question
{
NameOfQuestion = "Elvis Presley performed the song Hound dog. Please continue the lyrics to the song: You ain't nothing but a hound dog:",
Options = new List<string>() { "Party'n all the time", "Lying all the time", "Crying all the time", "Smiling everytime" },
Answer = "Crying all the time",
Category = "Music"
};
Question q20 = new Question
{
NameOfQuestion = "Who performed the song: Like a virgin?",
Options = new List<string>() { "Madonna", "Rihanna", "Britney Spears", "Cher" },
Answer = "Madonna",
Category = "Music"
};
Question q21 = new Question
{
NameOfQuestion = "Walter White är en högskolelärare som börjar att tillverka droger. Vad heter denna serie?",
Options = new List<string>() { "Game Of Thrones", "Drugs & Teach", "Breaking Bad", "Cocaine & Clementine" },
Answer = "Breaking Bad",
Category = "Film & TV-Serie"
};
Question q22 = new Question
{
NameOfQuestion = "I sagan om ringen finns det en liten hobbit som blivit förvriden av mörkret. Han mumlar ofta: my precious... Vad heter denna karaktär?",
Options = new List<string>() { "Smeagol", "Reagol", "Chero", "Mearo" },
Answer = "Smeagol",
Category = "Film & TV-Serie"
};
Question q23 = new Question
{
NameOfQuestion = "Vilken film har högst betyg på rating-sidan IMDB?",
Options = new List<string>() { "Gudfadern", "The Dark Knight", "Nyckeln till frihet", "Schindler's List" },
Answer = "Nyckeln till frihet",
Category = "Film & TV-Serie"
};
Question q24 = new Question
{
NameOfQuestion = "Vilken TV-serie har högst betyg på rating-sidan IMDB?",
Options = new List<string>() { "Planet Earth", "Planet Earth II", "Breaking Bad", "Band of Brothers" },
Answer = "Planet Earth II",
Category = "Film & TV-Serie"
};
Question q25 = new Question
{
NameOfQuestion = "Vad heter det svenska företaget som fram till 2012 tillverkade bilar? De kanske är mest kända för sina flygplan.",
Options = new List<string>() { "Volvo", "Audi", "Saab", "Gripen" },
Answer = "Saab",
Category = "Bilar"
};
Question q26 = new Question
{
NameOfQuestion = "Vad heter företaget från Ängelholm som tillverkar världens snabbaste bilar?",
Options = new List<string>() { "Hyundai", "Roendi", "Polestar", "Koenigsegg" },
Answer = "Koenigsegg",
Category = "Bilar"
};
Question q27 = new Question
{
NameOfQuestion = "Volvo är ett stort bilföretag som är baserat i Göteborg, Sverige. Men vad betyder volvo på latin?",
Options = new List<string>() { "Säkerhet", "Jag rullar", "Snabb och kompakt", "Säkert rullande" },
Answer = "Jag rullar",
Category = "Bilar"
};
Question q28 = new Question
{
NameOfQuestion = "Vad heter det kända Italienska bilmärket som är kända för sin röda färg?",
Options = new List<string>() { "Lamborghini", "Rolls Royce", "Audi", "Ferrari" },
Answer = "Ferrari",
Category = "Bilar"
};
Question q29 = new Question
{
NameOfQuestion = "Vilket är världens mest sålda TV-spel?",
Options = new List<string>() { "Counter Strike: Global Offensive", "Minecraft", "World Of Warcraft", "Grand Theft Auto V" },
Answer = "Minecraft",
Category = "TV-Spel"
};
Question q30 = new Question
{
NameOfQuestion = "Vad heter Mario's bror?",
Options = new List<string>() { "Bowser", "Toad", "Luigi", "Yoshi" },
Answer = "Luigi",
Category = "TV-Spel"
};
Question q31 = new Question
{
NameOfQuestion = "Vilken svensk skapade Minecraft?",
Options = new List<string>() { "Markus Persson", "Daniel Ek", "Joakim Larsson", "Max Pettersson" },
Answer = "Markus Persson",
Category = "TV-Spel"
};
Question q32 = new Question
{
NameOfQuestion = "Battle Royale är ett populärt läge. Det innebär att man möter andra lag och laget som är kvar sist vinner. Vilket är det populäraste Battle Royale Spelet?",
Options = new List<string>() { "Fortnite", "Apex Legends", "PUBG: Battlegrounds", "Call Of Duty: Warzone" },
Answer = "PUBG: Battlegrounds",
Category = "TV-Spel"
};
Questions.AddRange(new List<Question> { q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, q30, q31, q32 });
}
This is the list I would like to use, but I'm not sure how to only call the golf questions or how to only call the movies questions etc.
Right now I have a list for each category, so I'm calling the lists in blazor like this:
#if (questionIndex5 < QuestionsGolf.Count)
{
<div class="app-title">
#QuestionsGolf[questionIndex5].Category
</div>
<div class="quiz-header">
#QuestionsGolf[questionIndex5].NameOfQuestion
</div>
<div class="quiz-body">
#foreach (var option2 in QuestionsGolf[questionIndex5].Options)
{
<OptionCard Option="#option2" OnOptionSelected="OptionSelectedSolo"></OptionCard>
}
</div>
}
questionIndex5 is just declared as 0 and it ++'s when selecting an option in OnOptionSelected.
Anyone got any tips for me how too proceed? :)
The other answers already tell you how to filter by category:
IEnumerable<Question> golfQuestions = Questions
.Where(question => question.Category.Equals("Golf"));
// or
List<Question> golfQuestionList = Questions
.Where(question => question.Category.Equals("Golf"))
.ToList();
You seem to be confused how to display this. Often, when working with Lists / IEnumerables we want to display all of them. This could look something like this:
#foreach (Question question in golfQuestions)
{
<div class="app-title">
#question.Category
</div>
<div class="quiz-header">
#question.NameOfQuestion
</div>
<div class="quiz-body">
#foreach (var option2 in question.Options)
{
<OptionCard Option="#option2" OnOptionSelected="OptionSelectedSolo">
</OptionCard>
}
</div>
}
If you only want to display a single question, converting to an IEnumerable makes little sense. I would suggest adding .ToArray(), but .ToList() works as well. Here is an example of displaying the third golf question:
Question[] golfQuestions = Questions
.Where(question => question.Category.Equals("Golf"))
.ToArray();
Question myQuestion = gofQuestions[2];
<div class="app-title">
#myQuestion.Category
</div>
...
Anyone got any tips for me how too proceed? :)
Here's a slightly different implementation of your code that demonstrates some of the principles and patterns you can apply to help structure what your trying to do.
First a service for your data. You need to separate out the actual data pipeline from you UI. I use records to make the data in the data pipeline immutable (Read Only).
Your data object:
public record Question
{
public string NameOfQuestion { get; init; } = string.Empty;
public IEnumerable<string> Options { get; init; } = Enumerable.Empty<string>();
public string Answer { get; init; } = string.Empty;
public string Category { get; init; } = string.Empty;
}
Here's a demo QuestionProvider. Normally this will interface with a database or API so I've made it async.
public class QuestionProvider
{
private List<Question> _questions = new();
public Task Loading = Task.CompletedTask;
public QuestionProvider()
=> this.Loading = this.LoadQuestions();
public async ValueTask<IEnumerable<Question>> GetQuestions(QuestionQueryRequest request)
{
// Pretend I'm an async database or an API call
await Task.Delay(100);
var query = _questions.AsEnumerable();
if (request.Category is not null)
query = query.Where(item => item.Category.Equals(request.Category, StringComparison.CurrentCultureIgnoreCase));
return query;
}
public async ValueTask<IEnumerable<string>> GetCategories()
{
await Task.Delay(100);
return _questions.DistinctBy(item => item.Category).Select(item => item.Category);
}
private async Task LoadQuestions()
{
Question q1 = new Question
{
NameOfQuestion = "Vem är världens bästa golfspelare?",
Options = new List<string>() { "Tiger Woods", "Matt Kuchar", "S.H. Kim", "Adam Scott" },
Answer = "Tiger Woods",
Category = "Golf"
};
// your existing code
// pretend I'm a async task
await Task.Delay(100);
}
}
And then the View to manage the data for the UI page/component:
public class QuestionPresenter
{
private readonly QuestionProvider _questionProvider;
private bool _hasLoaded;
public IEnumerable<string> Categories = Enumerable.Empty<string>();
public string? Category { get; set; }
public IEnumerable<Question> Questions { get; private set; } = Enumerable.Empty<Question>();
public QuestionPresenter(QuestionProvider questionProvider)
=> _questionProvider = questionProvider;
public async ValueTask GetQuestions()
{
// ensure the provider has loaded completely
if (!_hasLoaded)
await _questionProvider.Loading;
this.Questions = await _questionProvider.GetQuestions(new(this.Category));
}
public async ValueTask Load()
{
// ensure the provider has loaded completely
await _questionProvider.Loading;
_hasLoaded= true;
this.Categories = await _questionProvider.GetCategories();
}
}
Service registration:
builder.Services.AddScoped<QuestionProvider>();
builder.Services.AddTransient<QuestionPresenter>();
And finally a page to get and display the data:
#page "/"
#inject QuestionPresenter Presenter
<PageTitle>Index</PageTitle>
<select class="form-select" value="#this.Presenter.Category" #onchange=SetCategory>
#if (this.Presenter.Category is null)
{
<option selected disabled value="">-- Select a Category --</option>
}
#foreach (var category in Presenter.Categories)
{
<option value="#category">#category</option>
}
</select>
#foreach (var question in this.Presenter.Questions)
{
<div class="bg-light p-2 m-2">
<div>
Question: #question.NameOfQuestion
</div>
<div>
Options: #OptionsList(question.Options)
</div>
<div>
Answer: #question.Answer
</div>
</div>
}
#code {
protected async override Task OnInitializedAsync()
=> await this.Presenter.Load();
private async Task SetCategory(ChangeEventArgs e)
{
this.Presenter.Category = e.Value?.ToString() ?? null;
if (this.Presenter.Category is not null)
await Presenter.GetQuestions();
}
private RenderFragment<IEnumerable<string>> OptionsList => list => __builder =>
{
foreach(var item in list)
{
<span> #item;</span>
}
};
}
You can create a method using the LINQ method Where to achieve this:
private IEnumerable<Question> GetQuestionsForCategory(string category)
{
return Questions.Where(x => x.Category == category)
}
You can use where Questions.Where(x => x.Category == "Golf")
Or if you need to group questions by category then - Questions.GroupBy(x => x.Category) -- with this solution you will get all questions grouped into lists by their category
Related
How to add a new item into an specific position of a list of objects
I have two list of objects(authors1, authors2), notice the authors1 is already sorted by SDATE, what I want to do is add the authors2 items into authors1 keeping same order, notice that all new items added needs to go to the end of each group of items IList<Author> authors1 = new List<Author> { new Author { Book = "c#", Code="A11" , SDate = 1 }, new Author { Book = "c#", Code="A22" , SDate = 1 }, new Author { Book = "c#", Code="A31" , SDate = 1 }, new Author { Book = "js", Code="B43" , SDate = 2 }, new Author { Book = "js", Code="B33" , SDate = 2 }, new Author { Book = "js", Code="B41" , SDate = 2 }, new Author { Book = "java", Code="C27", SDate = 3 }, new Author { Book = "java", Code="C33", SDate = 3 }, new Author { Book = "java", Code="C78", SDate = 3 } }; IList<Author> authors2 = new List<Author> { new Author { Book = "c#", Code = "A21" }, new Author { Book = "java", Code = "C23" } }; EXPECTED IList<Author> authors1 = new List<Author> { new Author { Book = "c#", Code="A11", SDate = 1 }, new Author { Book = "c#", Code="A22", SDate = 1 }, new Author { Book = "c#", Code="A31", SDate = 1 }, new Author { Book = "c#", Code="A21", SDATE = 1 }, // new item added to the end of this group new Author { Book = "js", Code="B43", SDate = 2 }, new Author { Book = "js", Code="B33", SDate = 2 }, new Author { Book = "js", Code="B41", SDate = 2 }, new Author { Book="java", Code="C27", SDate=3 }, new Author { Book="java", Code="C33", SDate=3 }, new Author { Book="java", Code="C78", SDate=3 }, new Author { Book="java", Code="C23", SDATE=3 } // new item added to the end of this group }; how can I accomplish this functionality? I was trying with two foreach, and then push the items into a new list, please help IList<Author> response = new List<Author>(); foreach (var author in authors2.GroupBy(x => x.Book).ToList()) { foreach (var item in author) {
You could do something like: foreach(Author a in authors2) { Author b = authors1.Where(x => x.Book == a.Book).LastOrDefault(); if (b != null) { int index = authors1.IndexOf(b); a.SDate = b.SDate; authors1.Insert(index + 1, a); } }
How do I write a strongly typed query filter where an array is a sub-array or equal to another array in MondoDB using C# driver?
Model: { _id: "1025", CandidateName: "John" Activities:["Programming", "Gaming"] } ChoicheOfActivities = ["Programming", "Gaming", "Singing", "Acting"]; Candidate1 = {_id:"1", Name: "John", Activities: ["Programming", "Gaming"]}; Candidate2 = {_id:"2", Name: "Mike", Activities: ["Programming", "Singing"]}; Candidate3 = {_id:"3", Name: "Joey", Activities: ["Gaming","Programming", "Singing", "Acting"]}; Candidate4 = {_id:"4", Name: "Ross", Activities: ["Programming", "Kayaking"]}; I want to filter the candidates who have activities that are sub or equal set to the ChoiceOfAtivities. After applying the filter I want the results to be Candidate1 = {_id:"1", Name: "John", Activities: ["Programming", "Gaming"]}; Candidate2 = {_id:"2", Name: "Mike", Activities: ["Programming", "Singing"]}; Candidate3 = {_id:"3", Name: "Joey", Activities: ["Gaming","Programming", "Singing", "Acting"]}; Candidate3 won't be selected because it has an activity "Kayaking" which is not in the ChoiceOfAtivities. Note: I want to apply this when filtering not on a list or an Enumerable.
#varman query is correct, however, this is how we'd express it as C#/.NET We'd start by creating a class that represents our document: class Candidate { public string Id { get; set; } public string Name { get; set; } public string[] Activities { get; set; } } Then to get things started we'll just connect to mongo and insert your sample data in to the test database. var client = new MongoClient(); var db = client.GetDatabase("test"); var collection = db.GetCollection<Candidate>("candidates"); var candidate1 = new Candidate { Id = "1", Name = "John", Activities = new[] { "Programming", "Gaming" } }; var candidate2 = new Candidate { Id = "2", Name = "Mike", Activities = new[] { "Programming", "Singing" } }; var candidate3 = new Candidate { Id = "3", Name = "Joey", Activities = new[] { "Gaming", "Programming", "Singing", "Acting" } }; var candidate4 = new Candidate { Id = "4", Name = "Ross", Activities = new[] { "Programming", "Kayaking" } }; await collection.InsertManyAsync(new[] { candidate1, candidate2, candidate3, candidate4 }); Now we'll build up some filters using the filter builder. var choiceOfActivities = new[] {"Programming", "Gaming", "Singing", "Acting"}; var filter = Builders<Candidate>.Filter.Not( Builders<Candidate>.Filter.ElemMatch(candidate => candidate.Activities, new BsonDocument("$nin", BsonArray.Create(choiceOfActivities)))); Then we can execute a find on our collection and get our the result var results = await collection.Find(filter) .ToListAsync(); foreach (var result in results) { Console.WriteLine($"{result.Id}, {result.Name}, {string.Join(" + ", result.Activities)}"); } // 1, John, Programming + Gaming // 2, Mike, Programming + Singing // 3, Joey, Gaming + Programming + Singing + Acting
You can do like this way db.collection.find({ Activities: { $not: { "$elemMatch": { $nin: [ "Programming", "Gaming", "Singing", "Acting" ] } } } }) Working Mongo playground
PayPal - How do I dynamically create line-items at the PayPal order request body?
I am currently trying to integrate the PayPal smart button to my asp.net core web application. I've referenced the following API documentation to set up a transaction with the PayPal API from my server: https://developer.paypal.com/docs/checkout/reference/server-integration/set-up-transaction/#on-the-server. However, the documentation hardcoded the line-items in the PayPal order request body. Right now, I have a variable called lineItems that contains a list of products that I want to send to PayPal. How do I dynamically create the lineItems at the BuildRequestBody() method? Below is my current code: Update I am still trying to solve this issue. Help is greatly appreciated! Update2 Still trying to solve this issue, help is greatly needed. Update3 Is anyone having the same issue as me? The documentation is extremely vague and I need help. Update4 No progress, still in need of help! public async Task<HttpResponse> createPaypalTransaction() { List<Product> lineItems = new List<Product>(); decimal totalPrice = 4.00; lineItems.Add(new Product { ProductId = 1, ProductName = "T-Shirt", Quantity = 2, Price = 2.00M }); lineItems.Add(new SanitizeProduct { ProductId = 2, ProductName = "Shoe", Quantity = 2, Price = 2.00M }); var request = new OrdersCreateRequest(); request.Prefer("return=representation"); request.RequestBody(BuildRequestBody()); //3. Call PayPal to set up a transaction var response = await PayPalClient.client().Execute(request); var result = response.Result<PayPalCheckoutSdk.Orders.Order>(); Console.WriteLine("Status: {0}", result.Status); Console.WriteLine("Order Id: {0}", result.Id); Console.WriteLine("Intent: {0}", result.Intent); Console.WriteLine("Links:"); foreach (LinkDescription link in result.Links) { Console.WriteLine("\t{0}: {1}\tCall Type: {2}", link.Rel, link.Href, link.Method); } AmountWithBreakdown amount = result.PurchaseUnits[0].Amount; Console.WriteLine("Total Amount: {0} {1}", amount.CurrencyCode, amount.Value); return response; } /* Method to generate sample create order body with CAPTURE intent #return OrderRequest with created order request */ private static OrderRequest BuildRequestBody(decimal totalPrice, List<SanitizeProduct> lineItems) { OrderRequest orderRequest = new OrderRequest() { Intent = "CAPTURE", ApplicationContext = new ApplicationContext { BrandName = "12345", UserAction = "CONTINUE", }, PurchaseUnits = new List<PurchaseUnitRequest> { new PurchaseUnitRequest{ ReferenceId = "PUHF", Description = "Customisable Goods", CustomId = "CUST-HighFashions", SoftDescriptor = "HighFashions", Amount = new AmountWithBreakdown { CurrencyCode = "SGD", Value = "230.00", Breakdown = new AmountBreakdown { // The subtotal for all items (quantity * price) ItemTotal = new Money { CurrencyCode = "SGD", Value = "230.00" }, } }, // How do i dynamically generate the list of items instead of hardcoding it? Items = new List<Item> { new Item { Name = "T-shirt", Description = "Green XL", Sku = "sku01", UnitAmount = new Money { CurrencyCode = "SGD", Value = "90.00" }, Tax = new Money { CurrencyCode = "SGD", Value = "10.00" }, Quantity = "1", Category = "PHYSICAL_GOODS" }, new Item { Name = "Shoes", Description = "Running, Size 10.5", Sku = "sku02", UnitAmount = new Money { CurrencyCode = "SGD", Value = "45.00" }, Tax = new Money { CurrencyCode = "SGD", Value = "5.00" }, Quantity = "2", Category = "PHYSICAL_GOODS" } }, } } }; return orderRequest; }
Find an Object that contains a string in a list of strings using LINQ
I have these lists: List<Author> MyAuthorList = new List<Author>(); List<string> BookListNo1 = new List<string>() { "The Girl with the Dragon Tattoo", "The Name of the Rose", "The Alienist", "In Cold Blood", "The Firm" }; List<string> BookListNo2 = new List<string>() { "And Then There Were None", "Mystic River", "The Shadow of the Wind", "Angels & Demons" , "The Big Sleep", "The Pelican Brief" }; List<string> BookListNo3 = new List<string>() { "One for the Money", "The Maltese Falcon", "In the Woods", "Presumed Innocent", "The Thirteenth Tale", "A is for Alibi", "Postmortem" }; List<string> BookListNo4 = new List<string>() { "Midnight in the Garden of Good and Evil", "The Strange Case of Dr. Jekyll and Mr. Hyde", "A Time to Kill", "The Historian" }; MyAuthorList.Add(new Author() { FirstName = "John", LastName = "Smith", Address = "Germany", Age = 13, NumberOfBooks = 5, EMBG = 123123, Books = BookListNo1, BankAccount = 1111, BankName = "Stupid Bank Name", BankAddress = "No One Knows" }); MyAuthorList.Add(new Author() { FirstName = "Max", LastName = "Warren", Address = "France", Age = 32, NumberOfBooks = 6, EMBG = 321321, Books = BookListNo2, BankAccount = 2222, BankName = "Stupid Bank Name", BankAddress = "Near The Bakery" }); MyAuthorList.Add(new Author() { FirstName = "Quinn", LastName = "Swanson", Address = "Russia", Age = 11, NumberOfBooks = 7, EMBG = 456456, Books = BookListNo3, BankAccount = 3333, BankName = "Stupid Bank Name", BankAddress = "On Some Desert Island" }); MyAuthorList.Add(new Author() { FirstName = "Ben", LastName = "Chaplin", Address = "Indonesia", Age = 34, NumberOfBooks = 4, EMBG = 654654, Books = BookListNo4, BankAccount = 4444, BankName = "Stupid Bank Name", BankAddress = "Moskovska 45" }); MyAuthorList.Add(new Author() { FirstName = "Jack", LastName = "Smirnoff", Address = "Germany", Age = 35, NumberOfBooks = 6, EMBG = 789789, Books = BookListNo2, BankAccount = 5555, BankName = "Stupid Bank Name 2", BankAddress = "Moskovska 452" }); Now I need to find all Authors from Germany with books that have the words "Girl" and "Blood" in them. This is what I have tried so far: I get all the authors from Germany like this: var germanAuthors = MyAuthorList.Where(x => x.Address.Contains("Germany")); ..and all the books that have the words "Blood" and "Girl" in them like this: var BooksOfAuthorsFromGermany = MyAuthorList.Where(x => x.Address.Contains("Germany")).SelectMany(y => y.Books); List<string> words = new List<string> { "Blood", "Girl"}; var searchedListOfBooks = BooksOfAuthorsFromGermany.Where(s => words.Any(w => s.Contains(w))); However, I can't combine these two together. Do I need to do this in a completely different way?
Try this var BooksOfAuthorsFromGermany = MyAuthorList .Where(x => x.Address.Contains("Germany") && x.Books.Where(a => a.Contains("Girl") || a.Contains("Blood")).Count() > 0) .ToList();
You can combine two query as follows , List<string> words = new List<string> { "Blood", "Girl"}; var AuthorList = MyAuthorList.Where(x => x.Address.Contains("Germany") && x.Books.Any(a => words.Any(w=> a.Contains(w)))).ToList();
According to your requirement you can use this var germanAuthors = MyAuthorList.Where(x => x.Address.Contains("Germany") && x.Books.Any(y => y.Contains("Blood") && y.Contains("Girl"))).Select(Z => Z.FirstName); var germanAuthorsWithBloodOrGirl = MyAuthorList.Where(x => x.Address.Contains("Germany") && x.Books.Any(y => y.Contains("Blood") || y.Contains("Girl"))).Select(Z => Z.FirstName);
NEST compound queries which must all be satisfied
var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo); var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom); var nameField = Infer.Field<Project>(f => f.Contact.Name); var active_date_to = new DateRangeQuery(){ Name = "toDate", Boost = 1.1, Field = "availablity.availableTo", GreaterThan = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; var active_date_from = new DateRangeQuery(){ Name = "from", Boost = 1.1, Field = "availablity.availableFrom", LessThanOrEqualTo = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; public ISearchResult<Project> Search(SearchCriteria criteria) {var ret = _client.Search<Project>(s => s.Query(q => active_date_from && active_date_to && q.Match(d => d.Query(criteria.FreeText)) ).From(criteria.CurrentPage).Size(criteria.Take) .From(criteria.CurrentPage) .Take(criteria.Take) ); result.Total = ret.Total; result.Page = criteria.CurrentPage; result.PerPage = criteria.Take; result.Results = ret.Documents; return result; } what im trying to do is get the results matching the freetext but are also withing the pricerange.. somehow though what i get is an invalid NEST response build from a unsuccessful low level call on POST... and in consequence an empty query. there are no compiling errors. does anyone have an idea where i could have gone wrong or what im missing? the other thing i tried was var mustClauses = new List<QueryContainer>(); mustClauses.Add(active_date_from); mustClauses.Add(active_date_to); mustClauses.Add(new TermQuery { Field = "contact.name", Value = criteria.FreeText }); var searchRequest = new SearchRequest<Project>() { Size = 10, From = 0, Query = new BoolQuery { Must = mustClauses } }; var ret = _client.Search<Project>(searchRequest); result.Total = ret.Total; result.Page = criteria.CurrentPage; result.PerPage = criteria.Take; result.Results = ret.Documents; which got me pretty much the same results.. (read: none) is there something im missing? edit: however.. this: var ret = _client.Search<Project>(s => s.Query(q => q.Match(m => m.Field(f => f.DisplayName).Query(criteria.FreeText)))); gives me exactly what i want (without the validation of the dates of course and only looking at one field)
In your first example, the match query is missing a field property which is needed for the query. Because of NEST's conditionless query behaviour, the query is not serialized as part of the request. The two date range queries are serialized however. Here's a simple example that you may find useful to get the correct query you're looking for void Main() { var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); var defaultIndex = "projects"; var connectionSettings = new ConnectionSettings(pool, new InMemoryConnection()) .DefaultIndex(defaultIndex ) .PrettyJson() .DisableDirectStreaming() .OnRequestCompleted(response => { if (response.RequestBodyInBytes != null) { Console.WriteLine( $"{response.HttpMethod} {response.Uri} \n" + $"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}"); } else { Console.WriteLine($"{response.HttpMethod} {response.Uri}"); } Console.WriteLine(); if (response.ResponseBodyInBytes != null) { Console.WriteLine($"Status: {response.HttpStatusCode}\n" + $"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" + $"{new string('-', 30)}\n"); } else { Console.WriteLine($"Status: {response.HttpStatusCode}\n" + $"{new string('-', 30)}\n"); } }); var client = new ElasticClient(connectionSettings); var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo); var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom); var nameField = Infer.Field<Project>(f => f.Contact.Name); var active_date_to = new DateRangeQuery { Name = "toDate", Boost = 1.1, Field = availableToField, GreaterThan = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; var active_date_from = new DateRangeQuery { Name = "from", Boost = 1.1, Field = availableFromField, LessThanOrEqualTo = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; var ret = client.Search<Project>(s => s .Query(q => active_date_from && active_date_to && q .Match(d => d .Query("free text") ) ) .From(0) .Size(10) ); } public class Project { public Availibility Availablity { get; set; } public Contact Contact { get; set; } } public class Contact { public string Name { get; set; } } public class Availibility { public DateTime AvailableFrom { get; set; } public DateTime AvailableTo { get; set; } } Your current query generates POST http://localhost:9200/projects/project/_search?pretty=true { "from": 0, "size": 10, "query": { "bool": { "must": [ { "range": { "availablity.availableFrom": { "lte": "2017-07-21T10:01:01.456794+10:00", "time_zone": "+01:00", "format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy", "_name": "from", "boost": 1.1 } } }, { "range": { "availablity.availableTo": { "gt": "2017-07-21T10:01:01.456794+10:00", "time_zone": "+01:00", "format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy", "_name": "toDate", "boost": 1.1 } } } ] } } } If a nameField is added as the field for the match query you get POST http://localhost:9200/projects/project/_search?pretty=true { "from": 0, "size": 10, "query": { "bool": { "must": [ { "range": { "availablity.availableFrom": { "lte": "2017-07-21T10:02:23.896385+10:00", "time_zone": "+01:00", "format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy", "_name": "from", "boost": 1.1 } } }, { "range": { "availablity.availableTo": { "gt": "2017-07-21T10:02:23.896385+10:00", "time_zone": "+01:00", "format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy", "_name": "toDate", "boost": 1.1 } } }, { "match": { "contact.name": { "query": "free text" } } } ] } } } Remove InMemoryConnection from ConnectionSettings if you actually want to execute the query against Elasticsearch and see the results. The range query is a structured query where a document either matches or doesn't match the predicate. Because of this, it can be wrapped in a bool query filter clause which will forgo calculating a score for it and perform better. Because no scoring occurs, boost is not needed. Putting this together var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo); var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom); var nameField = Infer.Field<Project>(f => f.Contact.Name); var active_date_to = new DateRangeQuery { Name = "toDate", Field = availableToField, GreaterThan = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; var active_date_from = new DateRangeQuery { Name = "from", Field = availableFromField, LessThanOrEqualTo = DateTime.Now, TimeZone = "+01:00", Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy" }; var ret = client.Search<Project>(s => s .Query(q => +active_date_from && +active_date_to && q .Match(d => d .Field(nameField) .Query("free text") ) ) .From(0) .Size(10) ); You may also want to explore modelling available from and to as a date_range type