Add a reference to another document in MongoDB C# MongoDB.Driver - mongodb

I have two classes:
public class MDBProducts
{
public string _id { get; set; }
public string order_number { get; set; }
[BsonIgnoreIfNull]
public List<Classes.MDBParts[]> partsId { get; set; }
}
public class MDBParts
{
public string _id { get; set; }
public string accountCode { get; set; }
}
With this lookup command mongodb embedded whole document information.
string param = "{$lookup: { from: 'Parts',localField: 'order_number',foreignField: 'accountCode',as:'partsId'} }";
BsonDocument document = BsonDocument.Parse(param);
var pipeline = new[] { document };
var result = Classes.MdB.connectDbProducts().Aggregate<MDBProducts>(pipeline).ToList();
I want to add to "partsId" only MDBParts class _id field. May you help me notice, how to do that?

References between Parts and Products collections
`var lookup1 = new BsonDocument
{
{
"$lookup",
new BsonDocument
{
{ "from", "Parts" },
{ "localField", "order_number" },
{ "foreignField", "productNumber" },
{ "as", "partsId" }
}
},
};
var lookup2 = new BsonDocument
{
{
"$project",
new BsonDocument
{
{ "partsId", "$partsId._id" },
{ "id", 1 }
}
}
};
var pipeline = new[] { lookup1, lookup2 };
var result = connectDbProducts().Aggregate<Products>(pipeline).ToList();
foreach (var item in result)
{
if (item.partsId.Count != 0)
{
var filterID = Builders<Products>.Filter.Eq(x => x._id, item._id);
var setTableTop = Builders<Products>.Update.Set(x => x.partsId, item.partsId);
connectDbProducts().UpdateOne(filterID, setTableTop);
}
else
{
var filterID = Builders<Products>.Filter.Eq(x => x._id, item._id);
var setTableTop = Builders<Products>.Update.Unset(x => x.partsId);
connectDbProducts().UpdateOne(filterID, setTableTop);
}
}`
Products Class
public class Products
{
public object _id { get; set; }
public string electricity_based_on { get; set; }
public double? full_price { get; set; }
public DateTime manufacturing_date { get; set; }
public string order_code { get; set; }
public string order_comment_names { get; set; }
public string order_name { get; set; }
public string order_number { get; set; }
public double? order_quantity { get; set; }
public double? unit_price { get; set; }
[BsonIgnoreIfNull]
public string user_name { get; set; }
[BsonIgnoreIfNull]
public DateTime user_checkTime { get; set; }
[BsonIgnoreIfNull]
public object order_comments { get; set; }
[BsonIgnoreIfNull]
public string tabletop_letter { get; set; }
[BsonIgnoreIfNull]
public string sub_3_4 { get; set; }
[BsonIgnoreIfNull]
public List<string> partsId { get; set; }
}
Connection to DB
public static IMongoCollection<Products> connectDbProducts()
{
try
{
MongoClient dbClient = new MongoClient(Properties.Resource1.mongoDB);
var db = dbClient.GetDatabase("Manufacturing");
var collection = db.GetCollection<Products>("Products");
return collection;
}
catch (Exception toMongoDBParts)
{
WriteLogFile("--MongoDB connection to Parts collection--", toMongoDBParts.StackTrace, toMongoDBParts.Message);
throw;
}
}

Related

EF Core 2.2 - can't add new record with link to already existing another one

My POCO classes:
[Table]
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<CategoryProduct> CategoryProducts { get; set; }
}
public class CategoryProduct
{
public int CategoryId { get; set; }
public int ProductId { get; set; }
public Category Category { get; set; }
public Product Product { get; set; }
}
[Table]
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<CategoryProduct> CategoryProducts { get; set; }
}
Here's a function for inserting new records:
async Task CreateProduct(Product dto)
{
await ctx.Products.AddAsync(dto);
await ctx.SaveChangesAsync();
}
In dto I pass the following JSON:
{
"name": "Gräff Stettin",
"categoryProducts": [{
"categoryId": 1,
"productId": 1,
"category": {
"id": 1,
"name": "Drinks"
}
}, {
"categoryId": 2,
"productId": 1,
"category": {
"id": 2,
"name": "Alcohol"
}
}
]
}
As a result, at SaveChangesAsync() I get an exception with message regarding attempt to insert already existing Category. Tracing shows the following query:
INSERT INTO "Category" ("Id", "Name") VALUES (#p0, #p1);
How should I change my CreateProduct() method to avoid attempts to add categories with already existing categoryId?
you can use AutoMapper and ignore category =
var config = new MapperConfiguration(cfg => cfg.CreateMap<categoryProductsDto,categoryProducts>())
.ForMember(u => u.Category, options => options.Ignore());
and use mapper =
var mapper = config.CreateMapper();
categoryProducts entity = mapper.Map<categoryProducts>(input);
await _categoryProductsRepository.InsertAndGetIdAsync(entity);

I can't retrieve data from many to many relationship to my ViewModel

I have the Map table that relates to the Day table in a many-to-many relationship.
So, I created the MapDay table according to the EF documentation.
The tables that are not related from many to many, I return without problems...
This is my controller, and I'm using viewmodels...
[HttpGet("getmaps")]
public async Task<ActionResult<IEnumerable<MapViewModel>>> GetMap()
{
var maps = _mapper.Map<IEnumerable<MapViewModel>>(await _mapRepository.GetMaps());
if(maps.Count() > 0) return Ok(maps);
return NotFound();
}
This is my MapViewModel:
public class MapViewModel : MainViewModel
{
public Guid UserId { get; set; }
public double Lng { get; set; }
public double Lat { get; set; }
public AddressViewModel Address { get; set; }
/* EF Relations */
public ItemMapViewModel ItemMap { get; set; }
public IEnumerable<MapDayViewModel> MapDay { get; set; } //testing
public IEnumerable<DayViewModel> Day { get; set; } // need this?
}
And my repository with the query:
public async Task<IEnumerable<Map>> GetMaps()
{
return await Db.Maps.AsNoTracking()
.Include(i => i.Address)
.Include(it => it.ItemMap)
.Include(mp => mp.MapDay).ThenInclude(mp => mp.Day)
.ToListAsync();
}
This is my result JSON:
[
{
"userId": "705cbdaf-86e9-4759-8f85-4fa6f3560726",
"lng": 0.0,
"lat": 0.0,
"address": {
"street": "st 123",
"number": "12",
"apt": "34",
"area": "AreaT",
"zip": "123456789",
"city": "Belo ",
"state": "ST",
"id": "ba3e7a68-63eb-4383-b980-14dea9615072"
},
"itemMap": {
"id": "353ccb80-b9fd-4469-9270-6a399ad37201",
"item": "Item1"
},
"mapDay": [
{
"mapId": "719da65c-42c9-4954-a750-e0b90e82461e",
"dayId": "5b444e8e-642f-4175-9329-9ef4a0f7aa87"
}
],
"day": null,
"id": "719da65c-42c9-4954-a750-e0b90e82461e"
}
]
Using aspnet core 3.1
So, what can I do to return the days of this map?
Using aspnet core 3.1 So, what can I do to return the days of this
map?
If you want to include Day data in the returned results of IEnumerable<MapViewModel> type, you really need to add public IEnumerable<DayViewModel> Day {get; set;} to MapViewModel.
Since you did not provide your automapper code, I will complete your requirements based on the code you gave.
Here I will simplify your model as follows:
Models:
public class Map
{
public int MapId { get; set; }
public string MapName { get; set; }
public ICollection<MapDay> MapDay { get; set; }
}
public class Day
{
public int DayId { get; set; }
public string DayName { get; set; }
public ICollection<MapDay> MapDay { get; set; }
}
public class MapDay
{
public int MapId { get; set; }
public Map Map { get; set; }
public int DayId { get; set; }
public Day Day { get; set; }
}
ViewModels:
public class MapViewModel
{
public int MapId { get; set; }
public string MapName { get; set; }
public IEnumerable<MapDayViewModel> MapDay { get; set; } //testing
public IEnumerable<DayViewModel> Day { get; set; } // need this?
}
public class DayViewModel
{
public int DayId { get; set; }
public string DayName { get; set; }
}
public class MapDayViewModel
{
public int MapId { get; set; }
public int DayId { get; set; }
}
Here is the detailed Automapper code to convert data from Models to ViewModels:
[HttpGet("getmaps")]
public async Task<ActionResult<IEnumerable<MapViewModel>>> GetMap()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Map, MapViewModel>()
.ForMember(dest => dest.MapId, opt => opt.MapFrom(s => s.MapId))
.ForMember(dest => dest.MapName, opt => opt.MapFrom(s => s.MapName))
.ForMember(x => x.MapDay, opt => opt.MapFrom(model => model.MapDay))
.ForMember(x => x.Day, opt => opt.MapFrom(model => model.MapDay.Select(x => x.Day)));
cfg.CreateMap<MapDay, MapDayViewModel>()
.ForMember(dest => dest.MapId, opt => opt.MapFrom(src => src.MapId))
.ForMember(dest => dest.DayId, opt => opt.MapFrom(src => src.DayId));
cfg.CreateMap<Day, DayViewModel>()
.ForMember(dest => dest.DayId, opt => opt.MapFrom(src => src.DayId))
.ForMember(dest => dest.DayName, opt => opt.MapFrom(src => src.DayName));
});
IMapper _mapper = config.CreateMapper();
var maps = _mapper.Map<IEnumerable<MapViewModel>>(await _mapRepository.GetMaps());
if (maps.Count() > 0)
return Ok(maps);
return NotFound();
}
Here is the test result:

Cannot deserialize the current JSON array during API call

I was learning how to consume API's and got stuck with the error "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'NbaApi.Models.Standard' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly." Thank you in advance!
I have this json
{
"_internal": {
"pubDateTime": "2020-04-03 13:11:16.692 EDT",
"igorPath": "S3,1585933850069,1585933857347|router,1585933857347,1585933857352|domUpdater,1585933857484,1585933875507|feedProducer,1585933875618,1585933885453",
"xslt": "NBA/xsl/league/roster/marty_active_players.xsl",
"xsltForceRecompile": "true",
"xsltInCache": "false",
"xsltCompileTimeMillis": "253",
"xsltTransformTimeMillis": "7800",
"consolidatedDomKey": "prod__transform__marty_active_players__1989425396229",
"endToEndTimeMillis": "35384"
},
"league": {
"standard": [
{
"firstName": "Steven",
"lastName": "Adams",
"temporaryDisplayName": "Adams, Steven",
"personId": "203500",
"teamId": "1610612760",
"jersey": "12",
"isActive": true,
"pos": "C",
"heightFeet": "6",
"heightInches": "11",
"heightMeters": "2.11",
"weightPounds": "265",
"weightKilograms": "120.2",
"dateOfBirthUTC": "1993-07-20",
"teamSitesOnly": {
"playerCode": "steven_adams",
"posFull": "Center",
"displayAffiliation": "Pittsburgh/New Zealand",
"freeAgentCode": ""
},
"teams": [
{
"teamId": "1610612760",
"seasonStart": "2013",
"seasonEnd": "2019"
}
],
"draft": {
"teamId": "1610612760",
"pickNum": "12",
"roundNum": "1",
"seasonYear": "2013"
},
"nbaDebutYear": "2013",
"yearsPro": "6",
"collegeName": "Pittsburgh",
"lastAffiliation": "Pittsburgh/New Zealand",
"country": "New Zealand"
}
]
}
}
I have these model classes
public class Data
{
public League League { get; set; }
}
public class League
{
public Standard Standard { get; set; }
}
public class Standard
{
public List<Player> players { get; set; }
}
public class Player
{
public string FirstName { get; set; }
public string LastName { get; set; }
//other parameters are also in the model
}
And I use this method to consume the api and pass it to the model
class Program
{
static void Main(string[] args)
{
var data = new List<Data>();
Player player = new Player();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://data.nba.net/10s/prod/v1/2019/players.json");
//HTTP GET
var responseTask = client.GetAsync("");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<List<Data>>();
readTask.Wait();
data = readTask.Result;
foreach (var item in data)
{
var league = item.League;
var standard = league.Standard;
var players = standard.players;
player = players.Where(p => p.LastName == "Adams").First();
}
}
else
{
throw new Exception(result.ReasonPhrase);
}
}
Console.WriteLine(player.LastName);
Console.ReadLine();
}
}
You need change your model as below
public class TeamSitesOnly
{
public string playerCode { get; set; }
public string posFull { get; set; }
public string displayAffiliation { get; set; }
public string freeAgentCode { get; set; }
}
public class Team
{
public string teamId { get; set; }
public string seasonStart { get; set; }
public string seasonEnd { get; set; }
}
public class Draft
{
public string teamId { get; set; }
public string pickNum { get; set; }
public string roundNum { get; set; }
public string seasonYear { get; set; }
}
public class Standard
{
public string firstName { get; set; }
public string lastName { get; set; }
public string temporaryDisplayName { get; set; }
public string personId { get; set; }
public string teamId { get; set; }
public string jersey { get; set; }
public bool isActive { get; set; }
public string pos { get; set; }
public string heightFeet { get; set; }
public string heightInches { get; set; }
public string heightMeters { get; set; }
public string weightPounds { get; set; }
public string weightKilograms { get; set; }
public string dateOfBirthUTC { get; set; }
public TeamSitesOnly teamSitesOnly { get; set; }
public List<Team> teams { get; set; }
public Draft draft { get; set; }
public string nbaDebutYear { get; set; }
public string yearsPro { get; set; }
public string collegeName { get; set; }
public string lastAffiliation { get; set; }
public string country { get; set; }
}
public class League
{
public List<Standard> standard { get; set; }
}
public class Data
{
public League league { get; set; }
}
You can use online tool to convert JSON object to C# class structure by http://json2csharp.com/
Change your model (since standard is an array, not an object):
public class League
{
public List<Player> Standard { get; set; }
}
The response object has structure:
{
"league": {
"standard": [...]
}
}
While your current model tries to deserialize:
{
"league": {
"standard": {
"players": [...]
}
}
}

.Net core with Mongodb

I am new to mongodb i am trying to insert a data into my collection using mongodb shell
User.cs
public class User
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("userName")]
public string? UserName { get; set; }
[BsonElement("workDay")]
public IEnumerable<WorkDay>? WorkDay { get; set; }
[BsonElement("emailAddress")]
public string? EmailAddress { get; set; }
[BsonElement("sendEventsOutsideWorkHours")]
public bool? SendEventsOutsideWorkHours { get; set; }
[BsonElement("sendReportOutsideWorkHours")]
public bool? SendReportsOutsideWorkHours { get; set; }
[BsonElement("timeZoneOffset")]
public int? TimeZoneOffset { get; set; }
}
Workday.cs
public class WorkDay
[BsonElement("dayOfWeek")]
public DayOfWeek DayOfWeek { get; set; }
[BsonElement("startTime")]
public WorkDayBoundary _StartTime { get; set; }
public TimeSpan StartTime
{
get
{
return new TimeSpan(_StartTime.Hours, _StartTime.Minutes, 0);
}
}
[BsonElement("endTime")]
public WorkDayBoundary _EndTime { get; set; }
public TimeSpan EndTime
{
get
{
return new TimeSpan(_EndTime.Hours, _EndTime.Minutes, 0);
}
}
}
public class WorkDayBoundary
{
[BsonElement("hours")]
public int Hours { get; set; }
[BsonElement("minutes")]
public int Minutes { get; set; }
}
and here is my code in mongodb shell
db.Users.insertMany([{
'userName': 'Testing123',
'workDay': {
'dayOfWeek': 0,
'startTime': { 'hours': 5, 'minutes': 23 },
'endTime': { 'hours': 5, 'minutes': 23 }
},
'emailAddress': 'thisismymail#email.com',
'sendEventsOutsideWorkHours': 1,
'sendReportOutsideWorkHours': 1,
'timeZoneOffset': 5.00
},
{
'userName': 'Something999',
'workDay': {
'dayOfWeek': 1,
'startTime': { 'hours': 1, 'minutes': 55 },
'endTime': { 'hours': 10, 'minutes': 33 }
},
'emailAddress': 'somethingas#email#email.com',
'sendEventsOutsideWorkHours': 0,
'sendReportOutsideWorkHours': 0,
'timeZoneOffset': 2.00
}
])
and while executing from .netcore application it was throwing an exception as
"FormatException: Cannot deserialize a 'List<WorkDay>' from BsonType 'Document'."

How to ignore a Navigation property ( not using Fluent API )

How can I ignore a navigation property without using FluentAPI in the onModelCreating for the below example:
Table Layout:
My Classes are below. When I use my contact to get results for PmActionDetail, the WorkTask table includes the AssetTypeWorkTask results, which is not the desired result.
public partial class PmActionDetail
{
public int PmActionDetlId { get; set; }
public int? AssetTypeWorkTaskId { get; set; }
public virtual AssetTypeWorkTask AssetTypeWorkTask { get; set; }
}
public partial class AssetTypeWorkTask
{
public AssetTypeWorkTask()
{
AssetPmTypeWorkTask = new HashSet<AssetPmTypeWorkTask>();
}
public int Id { get; set; }
public int? AssetTypeId { get; set; }
public int WorkTaskId { get; set; }
public virtual AssetType AssetType { get; set; }
public virtual AssetWorkTask WorkTask { get; set; }
public virtual ICollection<AssetPmTypeWorkTask> AssetPmTypeWorkTask { get; set; }
public virtual ICollection<PmActionDetail> PmActionDetail { get; set; }
}
public partial class AssetType
{
public AssetType()
{
AssetTypeWorkTask = new HashSet<AssetTypeWorkTask>();
}
public int AssetTypeId { get; set; }
public string AssetTypeDescription { get; set; }
public virtual ICollection<AssetTypeWorkTask> AssetTypeWorkTask { get; set; }
}
public partial class AssetWorkTask
{
public int Id { get; set; }
public string Desc { get; set; }
public virtual ICollection<AssetTypeWorkTask> AssetTypeWorkTask { get; set; }
}
Here is the context query I am running:
return await _context.PmActionDetail.Include("AssetTypeWorkTask").Include("AssetTypeWorkTask.WorkTask")
.Include("AssetTypeWorkTask.AssetType").ToListAsync();
These are the results. I do not want to show the relationship for assetTypeWorkTask under "workTask". I understand why it is perhaps showing it, since it is part of the relationship. However, its not the result I need.
[
{
"pmActionDetlId": 6008,
"pmActionHeadId": 1517,
"assetTypeWorkTaskId": 29,
"assetTypeWorkTask": {
"id": 29,
"assetTypeId": 31,
"workTaskId": 8,
"assetType": {
"assetTypeId": 31,
"assetTypeCategory": "ROOM",
"assetTypeWorkTask": []
},
"workTask": {
"id": 8,
"desc": "PM",
"active": 1,
"assetTypeWorkTask": [
{
"id": 20,
"assetTypeId": 20,
"workTaskId": 8,
"assetType": {
"assetTypeId": 20,
"assetTypeCategory": "CASEGOODS",
}
},
{
"id": 21,
"assetTypeId": 21,
"workTaskId": 8,
"assetType": {
"assetTypeId": 21,
"assetTypeCategory": "APPLIANCES",
},
}
]
},
"assetPmTypeWorkTask": [],
"pmActionDetail": null
}
}
]