I'm currently would like to sort a list of Object on LINQ, where I need to Sort and Remove Duplication if founded. It would be easier if I provide simple example for my scenario.
This is my current list (I have simplified it and sorted):
{
"data": [
{
"userActivityId": 17,
"deviceId": 2,
"name": "Apple Iphone X 2013 32 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 16,
"deviceId": 1,
"name": "Apple Iphone X 2013 16 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 15,
"deviceId": 1,
"name": "Apple Iphone X 2013 16 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 14,
"deviceId": 2,
"name": "Apple Iphone X 2013 32 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
]
}
Expected Result
What I really wanted:
{
"data": [
{
"userActivityId": 17,
"deviceId": 2,
"name": "Apple Iphone X 2013 32 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 16,
"deviceId": 1,
"name": "Apple Iphone X 2013 16 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
]
}
Here we can see then userActivityId 15 and 14 is removed, because the name already existed there.
So we can sort unique by using name.
What I have tried
First Attempt
This is the original code for the sorting functionality.
var data = new leapserverdbContext().TbUserActivity
.OrderByDescending(id => id.UserActivityId)
.Select(sel => new
{
sel.UserActivityId,
sel.TbDevice.DeviceId,
Name = sel.TbDevice.TbDeviceBrand.Name + " " + sel.TbDevice.Name +
" " + sel.TbDevice.TbDeviceYear.Year + " " + sel.TbDevice.TbDeviceSize.Size,
sel.TbDevice.IconResource
})
.ToList();
Second Attempt
I try to put Distinct(), but it won't work because there is userActivityId and it is unique (because incrementing).
Third Attempt
I try to remove userActivityId, to avoid it being considered while Distinct(), but then my data wont be sorted. Because sorting depends
on userActivityId.
Forth Attempt
I tried using GroupBy (x => x.Name), so focus divide based on unique Name.
But it just start dividing them into array as provided below:
{
"data": [
[
{
"userActivityId": 16,
"deviceId": 1,
"name": "Apple Iphone X 2013 16 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 15,
"deviceId": 1,
"name": "Apple Iphone X 2013 16 GB",
"iconResource": "phone_apple_iphone_x.jpg"
}
],
[
{
"userActivityId": 17,
"deviceId": 2,
"name": "Apple Iphone X 2013 32 GB",
"iconResource": "phone_apple_iphone_x.jpg"
},
{
"userActivityId": 14,
"deviceId": 2,
"name": "Apple Iphone X 2013 32 GB",
"iconResource": "phone_apple_iphone_x.jpg"
}
]
]
}
Now it is sorted and divided based on their unique name. But the layout is complete different.
What in my mind would do is get the first array (As it is the latest), but how can I combine and produce the Expected Result (See Above).
Is there anyway to solve this small problem of mine?
Apart from using an EqualityComparer like previously suggested you could also just group your result on name-property since you in this case are using an anonymous type.
var data = new leapserverdbContext().TbUserActivity
.OrderByDescending(id => id.UserActivityId)
.Select(sel => new
{
sel.UserActivityId,
sel.TbDevice.DeviceId,
Name = sel.TbDevice.TbDeviceBrand.Name + " " + sel.TbDevice.Name +
" " + sel.TbDevice.TbDeviceYear.Year + " " + sel.TbDevice.TbDeviceSize.Size,
sel.TbDevice.IconResource
})
.GroupBy(x => x.Name)
.Select(g => g.First())
.ToList();
You can create an Equality Comparer:
public class ActivityComparer : IEqualityComparer<TbUserActivity>
{
public bool Equals(TbUserActivity x, TbUserActivity y)
{
if (x == null && y == null)
return true;
else if (x == null || y == null)
return false;
return x.name == y.name
}
public int GetHashCode(TbUserActivity obj)
{
return obj.userActivityId;
}
}
And then just:
result.Distinct(new ActivityComparer());
Related
I have the following docs in my DB:
{
Age : 10,
BPM : 20,
Price: 6
},
{
Age : 12,
BPM : 30,
Price: 9
},
{
Age : 15,
BPM : 40,
Price: 6
},
{
Age : 10,
BPM : 46,
Price: 7
},
{
Age : 20,
BPM : 60,
Price: 8
}
I need help to write an aggregate query to find out for groups (age range 10-15 & BPM 20-50), (age range 15 - 20 & BPM 40 - 90), What is the total sum of prices for each group of ranges. There can be few more groups of ranges.
When you have multiple conditions, one option is to use $switch:
db.collection.aggregate([
{$set: {
group: {$switch: {
branches: [
{case: {
$and: [
{$gte: ["$Age", 10]},
{$lt: ["$Age", 15]},
{$gte: ["$BPM", 20]},
{$lt: ["$BPM", 50]}
]
}, then: 1},
{case: {
$and: [
{$gte: ["$Age", 15]},
{$lt: ["$Age", 20]},
{$gte: ["$BPM", 40]},
{$lt: ["$BPM", 90]}
]
}, then: 2}
],
default: "Did not match"
}}
}},
{$group: {_id: "$group", totalSumOfPrices: {$sum: "$Price"}}}
])
See how it works on the playground example
I have a json as data as below :
[
{
"id": 1,
"shopname": "seven up",
"shopkeeper": "John",
"salesbooks": [
{
"bookid": 11,
"bookname": "Tom-story",
"catagories" : 1,
"soldout": false
},
{
"bookid": 12,
"bookname": "Iron-Man",
"catagories" : 2,
"soldout": true
}
]
},
{
"id": 2,
"shopname": "Richmond Shop",
"shopkeeper": "Jame",
"salesbooks": [
{
"bookid": 11,
"bookname": "Tom-story",
"catagories" : 2,
"soldout": false
},
{
"bookid": 13,
"bookname": "PeterPan",
"catagories" : 2,
"soldout": true
}
]
},
{
"id": 3,
"shopname": "Worchester Shop",
"shopkeeper": "Jame",
"salesbooks": [
{
"bookid": 15,
"bookname": "Jurias Park",
"catagories" : 1,
"soldout": false
},
{
"bookid": 16,
"bookname": "Champion",
"catagories" : 1,
"soldout": true
}
]
}
]
My expected result should be:
[
{
"id": 1,
"shopname": "seven up",
"shopkeeper": "John",
"salesbooks": [
{
"bookid": 11,
"bookname": "Tom-story",
"catagories" : 1,
"soldout": false
},
{
"bookid": 12,
"bookname": "Iron-Man",
"catagories" : 2,
"soldout": true
}
]
}
]
Normally, if require to get shop which have book on sales , I can do it
var bookshop = bookshops.where(w=>w.salesbooks.any(a=>a.soldout==false));
But this time, if I also want to filter out if count(salesbooks.catagories) > 1?
That mean I want to filter out id:2 bookshop , as both of salesbook.catagories are same.
How to write the linq in c#?
p.s. I try
var bookshop = bookshops.where(w=>w.salesbooks.any(a=>a.soldout==false) && w.salebooks.GroupBy(g=>g.catagories).count==1);
the result is still show Richmond shop
Thank you
If you just want to filter out bookshops with categories more than 1. In C# You can just group by categories and have a check for >1 rather than ==1 i.e.
C# code
var bookshop = bookshops.Where(w => w.salesbooks.Any(a => a.soldout == false) && w.salesbooks.GroupBy(g => g.catagories).Count() > 1;
you can use another clause like
var bookshop = bookshops.Where(w => w.salesbooks.Any(a => a.soldout == false) && !w.salesbooks.Any(a => a.catagories < 2) );
Hope this helps
In cosmos DB the document structure is like this
[
{
"id": "1",
"Plants": [
{
"PlantId": 3,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 4,
"UniqueQualityId": "3_pe55d74fc5sdfmsdfklms"
},
{
"PlantId": 10,
"UniqueQualityId": "3_pe55d7akjdsj6ysdssdsd"
},
{
"PlantId": 12,
"UniqueQualityId": "5_fdffpe55d7akjdsj6ysds"
}
],
"CompletionTime": 36
},
{
"id": "2",
"Plants": [
{
"PlantId": 3,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 4,
"UniqueQualityId": "3_pe55d74fc5sdfmsdfklms"
},
{
"PlantId": 3,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 5,
"UniqueQualityId": "3_pe55d7akjdsj6ysdssdsd"
}
],
"CompletionTime": 36
},
{
"id": "2",
"Plants": [
{
"PlantId": 10,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 11,
"UniqueQualityId": "3_pe55d74fc5sdfmsdfklms"
}
],
"CompletionTime": 36
}
]
I need to get the collection of plants that meets specific condition:
For example, the query is written as to fetch Plants along with some parent data where PlantId in ("3","4") , then the output am expecting is
[
{
"id": "1",
"Plants": [
{
"PlantId": 3,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 4,
"UniqueQualityId": "3_pe55d74fc5sdfmsdfklms"
}
],
"CompletionTime": 36
},
{
"id": "2",
"Plants": [
{
"PlantId": 3,
"UniqueQualityId": "3_pe55d74fc5f92b11ab3fe"
},
{
"PlantId": 4,
"UniqueQualityId": "3_pe55d74fc5sdfmsdfklms"
}
}
],
"CompletionTime": 36
}
]
Here in the plants array it should only contain the items that meet the filtered condition.
I have tried the following methods
SELECT root["Plants"],root.id FROM root
WHERE EXISTS(select value plant FROM plant in root.Plants WHERE plant.PlantId in ("3","4"))
SELECT root.id,root.Plants FROM root where ARRAY_CONTAINS(c.Plants,{"PlantId": "3"},true)
If any of the plant items meet the condition it is returning the entire plant array instead of specific items.
Is there any method where it will return only the specific array items that meet the condition?
You can use the following query to get the result to get the output you want:
SELECT
c.id,
ARRAY(
SELECT VALUE p
FROM p IN c.Plants
WHERE p.PlantId IN (3, 4)
) AS Plants,
c.CompletionTime
FROM c
Although my personal preference would be the query below that does the same, but creates a seperate item for every plant. From the context I understand that you are looking for specific plants and capture some parent data in the result. In that case it would make sense to have seperate results by the plant.
SELECT
c.id,
p AS Plant,
c.CompletionTime
FROM c
JOIN
(
SELECT VALUE p
FROM p IN c.Plants
WHERE p.PlantId IN (3, 4)
) AS p
I need to update point Description field highlighted inside the nested Document using C# Mongo DB driver. I can do this update successfully using following query.
Document Structure
{
"ControllerID": "testcon",
"CCNID": "testccn",
"TableGroup": 1,
"Tables": [
{
"ID": 0,
"TableGroupID": 1,
"Blocks": [
{
"ID": 0,
"TableID": 0,
"TableGroupID": 1,
"ControllerID": "testcon",
"Points": [
{
"BlockID": 0,
"TableGroupID": 1,
"ControllerID": "testcon",
"TableID": 0,
"PointDefinitionID": 23,
"Name": "Test Point",
"Description": "Hgfhdhfhey You" <----------- This field needs to be updated
},
{
"BlockID": 0,
"TableGroupID": 1,
"ControllerID": "testcon",
"TableID": 0,
"PointDefinitionID": 24,
"Name": "Test Point",
"Description": "Hgfhdhfhey You"
}
]
}
]
}
]
}
I can successfully update the point Description using this query.
db.ControllerPointCollection.updateOne({
"_id": "HRDC_testccn_0_34_1"
},
{
$set: {
"Tables.$[t].Blocks.$[b].Points.$[p].Description": "Hey You"
}
},
{
arrayFilters: [
{
"t.ID": 0
},
{
"b.ID": 0
},
{
"p.PointDefinitionID": 23
}
]
})
I tried using this filter and update object for the above operation
var pointFilter = Builders<Point>.Filter.Eq(p => p.PointDefinitionID, point.PointDefinitionID);
var blockFilter = Builders<Block>.Filter.Eq(b => b.ID, point.BlockID) & Builders<Block>.Filter.ElemMatch(b => b.Points, pointFilter);
var tableFilter = Builders<Table>.Filter.Eq(t => t.ID, point.TableID) & Builders<Table>.Filter.ElemMatch(t => t.Blocks, blockFilter);
var filter = Builders<ControllerPointDataDoc>.Filter.Eq(c => c.ID, point.ControllerID) & Builders<ControllerPointDataDoc>.Filter.ElemMatch(c => c.Tables, tableFilter);
var updater = Builders<ControllerPointDataDoc>.Update.Set(c => c.Tables[-1].Blocks[-1].Points[-1].Description, "Hey You");
operationResult.Data = await ControllerPointDataCollection.UpdateOneAsync(filter, updater);
but I am getting the following error.
A write operation resulted in an error.\r\n Too many positional (i.e. '$') elements found in path 'Tables.$.Blocks.$.Points'
In C# how can I select only "GroupType" from the json below.
Thanks.
{
"QnACollection": {
"QnA": [
{
"id": 11,
"question": "What was your childhood nickname?"
},
{
"id": 12,
"question": "In what city was your mother born?"
},
{
"GroupType": "RUN",
"id": 45,
"question": "What is the first name?"
}
]
}
}
Using Json.Net
var value = (string)JObject.Parse(json)
.Descendants().OfType<JProperty>()
.FirstOrDefault(p => p.Name == "GroupType");