Using this put as a template and running all the code in LINQPad I was able to create your JSON structure and filter expression.
Below is the put I used:
test.Put("myset1", 6, new Dictionary<string, object>() {{"bCustId", 123},
{"bMonth", "may"},
{"bCategory", 6},
{"bOrdDtls", new object[] { new Dictionary<string,object>() {{"status","shipped"},
{"properties", new object[]
{ new Dictionary<string,object>()
{{"values",
new object[] {
new Dictionary<string,object>()
{{"ordDt", "2024-05-15"}}}},
{"itemCat", 1237}
}}}}}}
});
After putting several rows, I dump the set in JSON format:
test.myset1.ToJson().ToString()
[
{
"_id": 6,
"bCustId": 123,
"bMonth": "may",
"bCategory": 6,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1237,
"values": [
{
"ordDt": "2024-05-15"
}
]
}
],
"status": "shipped"
}
]
},
{
"_id": 3,
"bCustId": 123,
"bMonth": "may",
"bCategory": 5,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1234,
"values": [
{
"ordDt": "2024-05-15"
}
]
}
],
"status": "shipped"
}
]
},
{
"_id": 4,
"bCustId": 123,
"bMonth": "may",
"bCategory": 6,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1236,
"values": [
{
"ordDt": "2024-05-15"
}
]
}
],
"status": "shipped"
}
]
},
{
"_id": 2,
"bCustId": 123,
"bMonth": "may",
"bCategory": 5,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1234,
"values": [
{
"ordDt": "2024-05-14"
}
]
}
],
"status": "shipped"
}
]
},
{
"_id": 1,
"bCustId": 123,
"bMonth": "may",
"bCategory": 5,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1234,
"values": [
{
"ordDt": "2024-05-14"
}
]
}
],
"status": "shipped"
}
]
},
{
"_id": 5,
"bCustId": 123,
"bMonth": "may",
"bCategory": 6,
"bOrdDtls": [
{
"properties": [
{
"itemCat": 1236,
"values": [
{
"ordDt": "2024-05-15"
}
]
}
],
"status": "shipped"
}
]
}
]
Since you have embedded arrays there is no way to “scan” these arrays using Filter Expressions. Instead you must use a index (position) into the array to obtain the value. This is done via the CTX functions. The CTX allows you to navigate nested (embedded) collections until you find the value you require.
Below is the code required to obtain the record you are looking for:
test.myset1.Query(
Exp.And(
// Apply first filter on bin bMonth (secondary index) for best performance when using
// a secondary index.
Exp.EQ(Exp.StringBin("bMonth"), Exp.Val("may")),
Exp.EQ(Exp.IntBin("bCategory"), Exp.Val(5)),
/*bMonth = May
bCategory = 5
bOrdDtls[n].status = shipped
bOrdDtls[n].properties[m].values[One of the values].ordDt = 2024-05-14
bOrdDtls[n].properties[m].itesmCat = 1234
*/
Exp.EQ(MapExp.GetByKey(MapReturnType.VALUE,Exp.Type.STRING,Exp.Val("status"),Exp.Bin("bOrdDtls",Exp.Type.LIST),
CTX.ListIndex(0)), //Must use CTX to return first elemnt in bOrdDtls
Exp.Val("shipped")),
Exp.EQ(MapExp.GetByKey(MapReturnType.VALUE, Exp.Type.STRING, Exp.Val("ordDt"), Exp.Bin("bOrdDtls", Exp.Type.LIST),
CTX.ListIndex(0), //First element in bOrdDtls list
CTX.MapKey(Value.Get("properties")),
CTX.ListIndex(0), //First element in list within properties
CTX.MapKey(Value.Get("values")),
CTX.ListIndex(0)), //return first element in values
Exp.Val("2024-05-14")),
Exp.EQ(MapExp.GetByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.Val("itemCat"), Exp.Bin("bOrdDtls", Exp.Type.LIST),
CTX.ListIndex(0), //First element in bOrdDtls list
CTX.MapKey(Value.Get("properties")),
CTX.ListIndex(0)), //return first element in properties
Exp.Val(1234))
)
)
Result:
Using the Aerospike LINQPad driver you can incremental test your filter expression, one filter at a time (that is what I did).
If your data you need to query on is not in a static position within your lists, you would need to increment the list position programmability or change your “bOrdDtls” structure to use maps.
I hope I represented your data correctly and my explanation and examples make sense!
Please let me know if this was helpful and if you have any additional questions.