How do I include a nested field from a object from Mongo? - c#

The Entities
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace HelloWorldApi.Entities;
public class Deck
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
public string Name { get; set; } = "";
public List<string> Cards { get; set; } = new();
}
public class Credentials
{
public string Username { get; set; } = "";
public string Password { get; set; } = "";
}
[BsonIgnoreExtraElements]
public class Account {
public string Status = "";
public string Type = "";
public Credentials Credentials = new();
}
[BsonIgnoreExtraElements]
public class Player
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = "";
public Account Account = new ();
public List<string> Roles { get; set; } = new ();
public List<Deck> Decks { get; set; } = new ();
public List<string> Cards { get; set; } = new ();
}
The service:
public List<Player> GetUsers()
{
return _players.FindSync<Player>(FilterDefinition<Player>.Empty).ToList();
}
Specifically, I want to include the Account.Credentials.Username, but not the password.

You need the mongo projection
The docs adds an example:
var filter = Builders<BsonDocument>.Filter.Eq("status", "A");
var projection = Builders<BsonDocument>.Projection.Include("item").Include("status").Exclude("_id");
var result = collection.Find<BsonDocument>(filter).Project(projection).ToList();
So you can do something like
var projection = Builders<Player>.Projection
.Include(x => x.Account.Credentials.Username)
.Exclude(x => x.Account.Credentials.Password);
return _players.FindSync<Player>(FilterDefinition<Player>.Empty)
.Project(projection)
.ToList();

Related

How do I include nested objects from a C# Mongo FindSync statement and exclude certain fields?

The Entities
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace HelloWorldApi.Entities;
public class Deck
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
public string Name { get; set; } = "";
public List<string> Cards { get; set; } = new();
}
public class Credentials
{
public string Username { get; set; } = "";
public string Password { get; set; } = "";
}
[BsonIgnoreExtraElements]
public class Account {
public string Status = "";
public string Type = "";
public Credentials Credentials = new();
}
[BsonIgnoreExtraElements]
public class Player
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = "";
public Account Account = new ();
public List<string> Roles { get; set; } = new ();
public List<Deck> Decks { get; set; } = new ();
public List<string> Cards { get; set; } = new ();
}
The service:
public List<Player> GetUsers()
{
return _players.FindSync<Player>(FilterDefinition<Player>.Empty).ToList();
}
Specifically, I want to include the Account.Credentials.Username, but not the password.

How to create multiple instances of a ViewModel based on the IEnumerable data object?

I have a technician repository returning 8 results. I want to instantiate the ViewModel properties with those results. How can I achieve that ?
public class TechnicianViewModel
{
public Guid ID { get; set; }
public string UserName { get; set; }
public string Bio { get; set; }
public string GenerateName()
{
string str = GenerateURL();
str = str + ".jpg";
return str;
}
public string GenerateURL()
{
string phrase = string.Format("{0}", UserName);
string str = phrase.ToLower();
str = Regex.Replace(str, #"\s", "-");
return str;
}
}
The value returned by the data object contains the 8 results grouped as the technician model.
And the Technician Model looks like this.
public class Technician
{
[ScaffoldColumn(false)]
[Key]
public Guid UserId { get; set; }
[Required]
public string UserName { get; set; }
[Required]
public bool Licensed { get; set; }
[Required]
public bool Insured { get; set; }
[Required]
public bool DrugTested { get; set; }
public string EducationalLevel { get; set; }
public string Specialities { get; set; }
public string Bio { get; set; }
[Required,Display(Name = "Date of Birth")]
public DateTime DOB { get; set; }
public bool IsFormerTech { get; set; }
public DateTime ExperienceDate { get; set; }
public string MobilePhone { get; set; }
[Required]
public string Branch { get; set; }
public DateTime ApprenticeshipStatusDate { get; set; }
public string ActivityStatus { get; set; }
public string ReviewURL { get; set; }
Edit:-
I have moved the query out of the constructor, now I will try to access it within the controller.
public class TechnicianController : Controller
{
private readonly AADataContext aADataContext;
private readonly UnitOfWork unitOfWork;
private readonly TechnicianViewModel TechnicianViewModel;
public TechnicianController(AADataContext context)
{
aADataContext = context;
unitOfWork = new UnitOfWork(aADataContext);
var data = unitOfWork.TechnicianRepository.GetAll().Where(c => c.Branch == "Calgary").Where(a => a.ActivityStatus == "Active");
}
I'd argue the query doesn't belong in a view model. If you want a collection of your view model then move this query out of the constructor. You can do it in the controller action.
public ActionResult GetTechnicians(string branch, string status)
{
var data = unitOfWork.TechnicianRepository.GetAll()
.Where(c => c.Branch == "Calgary")
.Where(a => a.ActivityStatus == "Active")
.Select(t => new TechnicianViewModel
{
Id = t.UserId,
UserName = t.UserName,
Bio = t.Bio
});
...
}
When you have a number of these or if you find yourself repeating this query move it to a new class.
public class TechnicianService
{
private AADataContext context;
public TechnicianService(AADataContext context)
{
this.context = context;
}
public IEnumerable<TechnicianViewModel> GetTechnicians(string branch, string status)
{
}
}

Program seems to ignore rest of the list

I am trying to make retrieve a certain string from a list of object in c#( let's call that list userlist)(the list has about 1600 elements in it and each object has about 15 different parameters).
So this is the code that I have:
private List<String> getGameList(CommandEventArgs e) {
List<String> allgames = new List<string>();
List<User> userlist = e.Server.Users.ToList();
foreach (User u in userlist)
{
if (u.CurrentGame.ToString() != "")
{
if (u.CurrentGame.Value.Name != null)
{
allgames.Insert(0, u.CurrentGame.Value.Name);
}
}
}
return allgames;
}
But it everytime that this bit of code runs the list that gets returned has only one or two results in it while it should retrieve a lot more.
To give more information about the code:
User is the object with about 15 parameters/objects under it
u.CurrentGame retrieves an object called "Game" that is under a "User"
u.CurrentGame.Value.Name is the string that I want to retrieve and add in the new "allgames" list
I know the Insert(0,String) is strange but for some reason a simple .Add didn't seem to work properly either
Any idea why I only have 1 or 2 results and not more while it should?
I can definitly provide more information if needed.
Thank you
Without seeing the complete code my guess is that you either have an early return or a break somewhere in your loop where you probably should have been using a continue instead to continue iterating through the list.
You should also probably be using string.IsNullOrEmpty(s) instead of the comparison with "".
That's all the help I can give with the information you've provided.
I did small experiment 3 cases, and all 3 cases works somehow:
using System;
using System.Collections.Generic;
using System.Linq;
namespace p44785433
{
class Program
{
static List<User> userList = UserFactory.GenerateUsers();
static void Main(string[] args)
{
Console.WriteLine("Number Of Users: {0}", userList.Count);
var x = getGameList(userList); // 1600 on output
var y = getGameListUpdated(userList); // 1600< on output depend of randomized empty name
var z = getGameListLinq(userList); // 1600< on output depend of randomized empty name
}
private static List<String> getGameList(List<User> parUserList)
{
List<string> allgames = new List<string>();
List<User> userlist = /*e.Server.Users.ToList();*/ parUserList;
foreach (User u in userlist)
{
if (u.CurrentGame.ToString() != "")
{
if (u.CurrentGame.Value.Name != null)
{
allgames.Insert(0, u.CurrentGame.Value.Name);
}
}
}
return allgames;
}
private static List<String> getGameListUpdated(List<User> parUserList)
{
List<string> allgames = new List<string>();
List<User> userlist = /*e.Server.Users.ToList();*/ parUserList;
foreach (User u in userlist)
{
if (!string.IsNullOrEmpty(u.CurrentGame.ToString()))
{
if (!string.IsNullOrEmpty(u.CurrentGame.Value.Name))
{
allgames.Insert(0, u.CurrentGame.Value.Name);
}
}
}
return allgames;
}
private static List<String> getGameListLinq(List<User> parUserList)
{
List<User> userlist = /*e.Server.Users.ToList();*/ parUserList;
var x = userList.Where(r => !string.IsNullOrEmpty(r.CurrentGame.ToString()) && !string.IsNullOrEmpty(r.CurrentGame.Value.Name)); // remove empty
var y = x.Select(r => r.CurrentGame.Value.Name); // select strings
var z = y.Reverse(); // reverse order instead of insert
return z.ToList();
}
}
internal class User
{
public Game CurrentGame { get; set; }
public string Par1 { get; set; }
public string Par2 { get; set; }
public string Par3 { get; set; }
public string Par4 { get; set; }
public string Par5 { get; set; }
public string Par6 { get; set; }
public string Par7 { get; set; }
public string Par8 { get; set; }
public string Par9 { get; set; }
public string Par10 { get; set; }
public string Par11 { get; set; }
public string Par12 { get; set; }
public string Par13 { get; set; }
public string Par14 { get; set; }
internal static User CreateDummy()
{
return new User()
{
CurrentGame = Game.CreateDummy(),
Par6 = UserFactory.Rnd.NextDouble().ToString(),
Par12 = UserFactory.Rnd.NextDouble().ToString()
};
}
}
internal static class UserFactory
{
static Random _rnd;
internal static Random Rnd
{
get
{
if (_rnd == null) _rnd = new Random();
return _rnd;
}
}
internal static List<User> GenerateUsers()
{
List<User> list = new List<User>();
for (int i = 0; i < (int)1600; i++)
{
list.Add(User.CreateDummy());
}
return list;
}
}
internal class Game
{
public Value Value { get; set; }
public string Par1 { get; set; }
public string Par2 { get; set; }
public string Par3 { get; set; }
public string Par4 { get; set; }
public string Par5 { get; set; }
public string Par6 { get; set; }
public string Par7 { get; set; }
public string Par8 { get; set; }
public string Par9 { get; set; }
public string Par10 { get; set; }
public string Par11 { get; set; }
public string Par12 { get; set; }
public string Par13 { get; set; }
public string Par14 { get; set; }
public override string ToString()
{
return Par6;
}
internal static Game CreateDummy()
{
return new Game()
{
Value = Value.CreateDummy(),
Par6 = UserFactory.Rnd.NextDouble().ToString(),
Par12 = UserFactory.Rnd.NextDouble().ToString()
};
}
}
internal class Value
{
public string Name { get; set; }
public string Par1 { get; set; }
public string Par2 { get; set; }
public string Par3 { get; set; }
public string Par4 { get; set; }
public string Par5 { get; set; }
public string Par6 { get; set; }
public string Par7 { get; set; }
public string Par8 { get; set; }
public string Par9 { get; set; }
public string Par10 { get; set; }
public string Par11 { get; set; }
public string Par12 { get; set; }
public string Par13 { get; set; }
public string Par14 { get; set; }
internal static Value CreateDummy()
{
return new Value()
{
Name = (UserFactory.Rnd.Next(10)!=0 ? string.Format("XXA{0}XAA", UserFactory.Rnd.NextDouble()): string.Empty),
Par5 = UserFactory.Rnd.NextDouble().ToString(),
Par11 = UserFactory.Rnd.NextDouble().ToString()
};
}
}
}

How to Manually mapa viewmodel with lists to dto

I'm new to backend development, having some trouble mapping a viewmodel to dto that has a list.
Can you help me figure out whats wrong with the mapper. The result is coming in correct from the dto. I have a list of 7 items. When it maps to the view they are gone.
Here is the viewmodel
public class StatisticsViewModel : BaseViewModel
{
public string StartDate { get; set; }
public string EndDate { get; set; }
public string ProviderId { get; set; }
public List<StatisticsTotalsViewModel> Totals { get; set; } = new List<StatisticsTotalsViewModel>();
public List<StatisticsProvidersViewModel> Providers { get; set; } = new List<StatisticsProvidersViewModel>();
}
public class StatisticsTotalsViewModel
{
public string PayerName { get; set; }
public string PayerType { get; set; }
public short Status { get; set; }
public int TotalCount { get; set; }
public decimal TotalBalance { get; set; }
}
Heres the dto
public class StatisticsDto
{
public string StartDate { get; set; }
public string EndDate { get; set; }
public string ProviderId { get; set; }
public List<StatisticsTotalsDto> Totals { get; set; } = new List<StatisticsTotalsDto>();
public List<StatisticsProvidersDto> Providers { get; set; } = new List<StatisticsProvidersDto>();
}
public class StatisticsTotalsDto
{
public string PayerName { get; set; }
public string PayerType { get; set; }
public short Status { get; set; }
public int TotalCount { get; set; }
public decimal TotalBalance { get; set; }
}
Here's the mapper
public static StatisticsViewModel MapToView(StatisticsDto dto)
{
var viewmodel = new StatisticsViewModel();
viewmodel.StartDate = dto.StartDate;
viewmodel.EndDate = dto.EndDate;
viewmodel.ProviderId = dto.ProviderId;
var dtoTotals = new List<StatisticsTotalsDto>();
var totals = new List<StatisticsTotalsViewModel>();
foreach (var item in dtoTotals)
{
var totalsModel = new StatisticsTotalsViewModel();
item.PayerName = totalsModel.PayerName;
item.PayerType = totalsModel.PayerType;
item.Status = totalsModel.Status;
item.TotalBalance = totalsModel.TotalBalance;
item.TotalCount = totalsModel.TotalCount;
totals.Add(totalsModel);
}
viewmodel.Totals = totals;
return viewmodel;
}
Problem in this line. Instead
var dtoTotals = new List<StatisticsTotalsDto>();
You need to receive list of StatisticsTotalsDto, instead of create new empty list
var dtoTotals = dto.Totals;
You can try Automapper.
Say for example:
public static StatisticsViewModel MapToView(StatisticsDto dto)
{
Mapper.Initialize(cfg => cfg.CreateMap<StatisticsDto, StatisticsViewModel>());
var ViewModel = Mapper.Map<StatisticsViewModel>(dto);
return viewModel;
}
Take a look at here to know more about Automapper. You can also check here and here if you face problem mapping list items.
P.S Don't forget to include Automapper to your project and add using Automapper() at the top where you are using it

Deserialising json C#

I have json as below:
{"data":[{"name":"123","pwd":123},{"name":"456","pwd":456},{"name":"789","pwd":789}],"duration":5309,"query":"myquery","timeout":300}
Using http://json2csharp.com/ I am deserialising it as below:
namespace Test
{
public class Info
{
public string name{ get; set; }
public string pwd{ get; set; }
}
public class Product
{
public Info[] data { get; set; }
public int duration { get; set; }
public string query { get; set; }
public int timeout { get; set; }
}
//code here, function start etc.
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new
StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Product myprod = JsonConvert.DeserializeObject<Product>(result);
var results = myprod.data;
}
}
The value of results is {Test.Info[0]} where Test is my namespace name. How do I obtain the actual data?
Your Info class should be
public class Info
{
public string name { get; set; }
public int pwd { get; set; }
}
This should work
var testJson = "{\"data\":[{\"name\":\"123\",\"pwd\":123},{\"name\":\"456\",\"pwd\":456},{\"name\":\"789\",\"pwd\":789}],\"duration\":5309,\"query\":\"myquery\",\"timeout\":300}";
var product = JsonConvert.DeserializeObject<Product>(testJson);

Categories

Resources