I am new to the MongoDB. I have one document named Documents
in which I have multiple data as mentioned below
Data 1 -
{
"ProjId": 18586,
"ArtifactAttributes": [
{
"AttributeName": "Author",
"AttributeValue": "XYZ"
},
{
"AttributeName": "Address",
"AttributeValue": "Addrr1"
},
{
"AttributeName": "Owner",
"AttributeValue": "manoj.naik"
}
]
}
Data 2 -
{
"ProjId": 18587,
"ArtifactAttributes": [
{
"AttributeName": "Author",
"AttributeValue": "ABC"
},
{
"AttributeName": "Address",
"AttributeValue": "Addrr2"
},
{
"AttributeName": "Owner",
"AttributeValue": "kumar.manoj"
}
]
}
Data - 3
{
"ProjId": 18588,
"ArtifactAttributes": [
{
"AttributeName": "Author",
"AttributeValue": "PQR"
},
{
"AttributeName": "Address",
"AttributeValue": "Addrr3"
},
{
"AttributeName": "Owner",
"AttributeValue": "kumar.manoj"
}
]
}
I want to return distinct value where AttributeName
is equals to Owner
.
Expected Result - [manoj.naik,kumar.manoj]
For that I have written code as below but it is not returning expected result instead of that it is returning all distinct values from AttributeValue
not specifically from AttributeName
where it has Owner
Result which I am getting is as below
[XYZ,Addrr1,manoj.naik,ABC,Addrr2,kumar.manoj,PQR,Addrr3]
My C# Code -
var ownerFilter = Builders<Documents>.Filter.ElemMatch(x => x.ArtifactAttributes, p => p.AttributeName.Equals("Owner"));
var ownerValueFieldDefinition = new StringFieldDefinition<Documents, string>("ArtifactAttributes.AttributeValue");
var distinctItems = _projectArtifacts.Distinct(ownerValueFieldDefinition, ownerFilter).ToList();
CodePudding user response:
It doesn't work because ElemMatch
matches any document that has an element with AttributeName == "Owner"
in its ArtifactAttributes
. It returns original unmodified documents, it doesn't magically remove values of ArtifactAttributes
that you don't need.
As far as I know, there is no elegant way to do what you want, but you can do this:
var distinctItems = _projectArtifacts
.Aggregate()
.Unwind(x => x.ArtifactAttributes)
.Match(x => x["ArtifactAttributes.AttributeName"] == "Owner")
.Group("{ _id: '$ArtifactAttributes.AttributeValue' }")
.ToList()
.Select(x => x["_id"].AsString)
.ToList();
Step-by-step explanation:
Aggregate
- start an aggregation pipeline.Unwind
- replace each document with its copies, each containing only one of the values ofArtifactAttributes
.Match
- filter documents, leaving only those whereAttributeName == "Owner"
.Group
- group documents byAttributeValue
. This allows to get all the distinct values in the_id
field.ToList
- get results from the database. Aggregation always returns a list of documents, not just values. So you have to do some more steps to get list of values.Select
andToList
- get list of values using LINQ.