API $expand and &count - dynamics-crm-365

Is it possible to use $expand but instead of returning a collection of objects, just return the count of objects?
For example, get an account and a count of its annotations in a single WebApi call
I've tried a few things.
Obvious attempt: accounts(6CDEEB72-2AC8-E711-A825-000D3AE0A7F8)?$select=name&$expand=Account_Annotation($count=true) returns all fields of all Annotations but doesn't count anything.
Next I tried accounts(6CDEEB72-2AC8-E711-A825-000D3AE0A7F8)?$select=name&$expand=Account_Annotation($select=annotationid&$count=true) returns an error: "Found an unbalanced bracket expression". I think this is related to the & symbol in the $expand
I found a non-crm blog that said this could be resolved with a ; but when I tried accounts(6CDEEB72-2AC8-E711-A825-000D3AE0A7F8)?$select=name&$expand=Account_Annotation($select=annotationid;$count=true) it doesn't give an error, but the $count instruction seems to be ignored
A crazy attempt of accounts(6CDEEB72-2AC8-E711-A825-000D3AE0A7F8)?$select=name&$count=Account_Annotation($select=annotationid) returns a "not a valid count" error
I'm guessing that this is not a valid combination, but I thought I would post here in case someone else has achieved this successfully.

I got this working, but I'm not sure it's what you are looking for exactly, it only works if I put the count before expand:
api/data/v9.0/cmnt_salesexample?
$select=endcustomeraccountid&$count=true&$expand=endcustomerid($select=accountid)
output:
{
"#odata.context": "https://xyz",
"#odata.count": 5000,
"value": [
{
"#odata.etag": "W/\"3560581422\"",
"endcustomerid": "54321"
},
{
"#odata.etag": "W/\"3510396844\"",
"endcustomerid": "12345"
},
...

Related

Mongoose Model.deleteMany() only deletes first element of matches

I'm trying to use the Model.deleteMany() function from mongoose. I'm trying to do something like this:
MyModel.deleteMany({"_id": {$in: ['objectid 1', 'objectid 2'
But this only deletes the first element of the matches from DB (in this case, if 'objectid 1' exists in the DB, it deletes that, but if it isn't nothing happens (both n and deletedCount is 0 in the returned data from the function). I tried using something other than the _id as a query, and this worked. If I had three elements with the same 'name' field, I could delete these.
I tried _id both with and without quotation marks. I also tried converting the object id strings to actual object ids before passing them to deleteMany, but this had no difference either. I have also of course tried to google this, but everything I've found are examples of usage, where it looks like I'm doing the exact same thing as the various blog posts.
I haven't added much code here because I don't really see what else I could be adding. I'm already printing out the input to the $in object, and this is correct. The strangest thing, I think, is that the first element of the list is deleted. Is it treated as a deleteOne request for some reason? are there any config options I need?
As per request, I've added the query and the documents I'd hope to delete:
//Request
MemberModel.deleteMany({"_id": {$in: [
5ee4f6308631dc413c7f04b4,
5ee4f6308631dc413c7f04b5,
5ee4f6308631dc413c7f04b6
]}};
//Expected to be deleted
[
{
"_id": "5ee4f62f8631dc413c7f04b5",
"firstName": "Name",
"lastName": "Nameson",
"__v": 0
},
{
"_id": "5ee4f62f8631dc413c7f04b6",
"firstName": "Other",
"lastName": "Person",
"__v": 0
}
]
If you have any ideas for what I could try, that would be much appreciated.

Convert Row Count to INT in Azure Data Factory

I am trying to use a Lookup Activity to return a row count. I am able to do this, but once I do, I would like to run an If Statement against it and if the count returns more than 20MIL in rows, I want to execute an additional pipeline for further table manipulation. The issue, however, is that I can not compare the returned value to a static integer. Below is the current Dynamic Expression I have for this If Statement:
#greater(int(activity('COUNT_RL_WK_GRBY_LOOKUP').output),20000000)
and when fired, the following error is returned:
{
"errorCode": "InvalidTemplate",
"message": "The function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type",
"failureType": "UserError",
"target": "If Condition1",
"details": ""
}
Is it possible to convert this returned value to an integer in order to make the comparison? If not, is there a possible work around in order to achieve my desired result?
Looks like the issue is with your dynamic expression. Please correct your dynamic expression similar to below and retry.
If firstRowOnly is set to true : #greater(int(activity('COUNT_RL_WK_GRBY_LOOKUP').output.firstRow.propertyname),20000000)
If firstRowOnly is set to false : #greater(int(activity('COUNT_RL_WK_GRBY_LOOKUP').output.value[zero based index].propertyname),20000000)
The lookup result is returned in the output section of the activity run result.
When firstRowOnly is set to true (default), the output format is as shown in the following code. The lookup result is under a fixed firstRow key. To use the result in subsequent activity, use the pattern of #{activity('MyLookupActivity').output.firstRow.TableName}.
Sample Output JSON code is as follows:
{
"firstRow":
{
"Id": "1",
"TableName" : "Table1"
}
}
When firstRowOnly is set to false, the output format is as shown in the following code. A count field indicates how many records are returned. Detailed values are displayed under a fixed value array. In such a case, the Lookup activity is followed by a Foreach activity. You pass the value array to the ForEach activity items field by using the pattern of #activity('MyLookupActivity').output.value. To access elements in the value array, use the following syntax: #{activity('lookupActivity').output.value[zero based index].propertyname}. An example is #{activity('lookupActivity').output.value[0].tablename}.
Sample Output JSON Code is as follows:
{
"count": "2",
"value": [
{
"Id": "1",
"TableName" : "Table1"
},
{
"Id": "2",
"TableName" : "Table2"
}
]
}
Hope this helps.
Do this - when you run the debugger look at the output from your lookup. It will give a json string including the alias for the result of your query. If it's not firstrow set then you get a table. But for first you'll get output then firstRow and then your alias. So that's what you specify.
For example...if you put alias of your count as Row_Cnt then...
#greater(activity('COUNT_RL_WK_GRBY_LOOKUP').output.firstRow.Row_Cnt,20000000)
You don't need the int function. You were trying to do that (just like I was!) because it was complaining about datatype. That's because you were returning a bunch of json text as the output instead of the value you were after. Totally makes sense after you realize how it works. But it is NOT intuitively obvious because it's coming back with data but its string stuff from json, not the value you're after. And functions like equals are just happy with that. It's not until you try to do something like greater where it looks for numeric value that it chokes.

Mongo Scala Driver: PullByFilter Based on Nested Field Value

I have a model band that contains a list of tours
Band:
{
name: String,
email: String,
createdAt: String,
tours: Tour[],
...
}
where a Tour is:
{
name: String,
region: String,
published: Boolean,
...
}
The goal is simply to create an end point that receives a Band Name and Tour Name deletes a tour based on this input.
The following works:
bandService.getBandByName(req.getParam("bandName")).flatMap{ b =>
val tour = b.tours.filter(t => t.name == req.getParam("tourName")).head
mongoDataBaseConnector.bands.findOneAndUpdate(
equal("bandName", req.getParam("bandName")),
pull("tours", tour)
).toFuture().flatMap(u => bandService.getBandByName(req.getParam("bandName")))
However, this requires me to first resolve the band by the name received first, filter, find the tour and pass in the exact object in to the pull I am trying to avoid this by using pullByFilter but can't seem to get this to work. Unfortunately couldn't find any examples of this function in the scala driver.
This is what I am trying:
mongoDataBaseConnector.bands.findOneAndUpdate(
and(
equal("bandName", req.getParam("bandName")),
equal("tours.name", req.getParam("tourName"))),
pullByFilter(and(
equal("tours.$.name", req.getParam("tourName")),
equal("tours.$.region", req.getParam("region"))
))
).toFuture().flatMap(u => bandService.getBandByName(req.getParam("bandName")))
this gives the following error:
com.mongodb.MongoCommandException: Command failed with error 2 (BadValue): 'Cannot apply $pull to a non-array value' on server cluster0-shard-00-01-sqs4t.mongodb.net:27017. The full response is {"operationTime": {"$timestamp": {"t": 1568589476, "i": 8}}, "ok": 0.0, "errmsg": "Cannot apply $pull to a non-array value", "code": 2, "codeName": "BadValue", "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1568589476, "i": 8}}, "signature": {"hash": {"$binary": "Qz/DqAdG11H8KRkW8gtvRAAE61Q=", "$type": "00"}, "keyId": {"$numberLong": "6710077417139994625"}}}}
Any ideas are appreciated. Is this even possible with this function?
Okay, I've been working on a nearly identical problem all day. What I have isn't great, but it's enough that I'm willing to accept it and hopefully someone will be able to make it into a more fully-formed solution. Or at least I can save someone else some time.
pullByFilter only accepts one argument. It seems that argument can be another Bson filter which is applied directly to each of the children, or a BsonValue that will be matched against. Since none of the Bson filters step into the child documents, you have to create a BsonValue, specifically, a document. I believe this should solve your problem:
mongoDataBaseConnector.bands.findOneAndUpdate(
and(
equal("bandName", req.getParam("bandName")),
equal("tours.name", req.getParam("tourName"))),
pullByFilter(BsonDocument().append("tours", BsonDocument()
.append("name", req.getParam("tourName"))
.append("region", req.getParam("region"))
))
).toFuture().flatMap(u => bandService.getBandByName(req.getParam("bandName")))
I would have liked to be able to switch back using Bson filters after getting to the inner document, but it seems that once you're in BsonValues, you can't go back.
Edit: To help whoever comes after me: I think there should be a way to solve this more cleanly with arrayFilters, but I haven't yet found it.

How to filter by count on gremlin map (OrientDB)

I have a somewhat similar business problem to - Gremlin filter by count
, but I'm running on OrientDB 3.0.16
This query:
g.V().hasLabel('skill').
groupCount()
Returns from OrientDB, as expected:
{
"result": [
{
"com": 1,
"netcompactframework": 1,
"netremoting": 2,
"netframework": 3,
"net": 1,
"netclr": 1
}
],
"elapsedMs": 18
}
I tried to apply an unfold and where filter after it:
g.V().hasLabel('skill').
groupCount().
unfold().
where(select(values).is(gt(1)))
But I get an error:
{
"errors": [
{
"reason": 501,
"code": 501,
"content": "java.lang.UnsupportedOperationException: Cannot convert netremoting=2 - class java.util.HashMap$Node to JSON"
}
]
}
It seems that problem is with unfold() as OrientDB is trying to convert the map entry string into JSON and fails
Any ideas?
Is this an OrientDB specific issue? Maybe there is another way to perform the same logic in gremlin?
That looks like a serialization error of some sort, but I'm not sure of the circumstance under which you are operating to get that problem. When you unfold() a Map, it gets converted to Java Map.Entry and returning that seems to be a problem for the serializer which along the way encounters the internal class HashMap$Node. I think you can work around this problem by folding back to a Map:
g.V().hasLabel('skill').
groupCount().
unfold().
where(select(values).is(gt(1))).
group().
by(keys).
by(select(values))
I would be curious to know what circumstances cause you to get that error. Standard GraphSON serializers in Gremlin Server should be able to handle HashMap$Node so it's curious that you'd be getting this problem at all.

Azure CosmosDB operation not supported when using $elemMatch and $in

I am doing a query like the following, which works fine with MongoDB, but sometimes fails with CosmosDB. I need it to work with both.
(XXX is a placeholder for any string value. All strings have unique values that are redacted for readability, and actual content should be of no significance.)
{
server_index: {
$elemMatch: {
server: "XXX",
index: "XXX",
delete_time: { $exists: false },
path: {
$in: ["XXX", "XXX", "XXX" ]
}
}
}
}
The schema of a document is somewhat like this:
{
...,
server_index: [
{
server: "XXX",
index: "XXX",
delete_time: ISODate(...), // optional
path: "XXX"
},
{...}, // same as above
...
],
...
}
This query sometimes works as expected with CosmosDB as well, but sometimes I also get the following response:
{
_t: "OKMongoResponse",
ok: 0,
code: 115,
errmsg: "Command is not supported",
$err: "Command is not supported"
}
What is especially strange is that the query seemingly succeeds, and the response above is returned by a "valid" cursor as the first document, which then causes my document parser "crash".
I am using the C++ legacy driver. Is this even supported by Cosmos DB?
(According to the developer I inherited this project from, it is, and as always when you inherit projects, it all worked fine according to the previous developer... So this may be due to a change in Cosmos DB, due to the nature of my test data, or who knows what...)
Side note: In MongoDB, there is a multi-key index on server_index, which looks like this:
{
"server_index.delete_time" : 1,
"server_index.server" : 1,
"server_index.index" : 1,
"server_index.path" : 1
}
Is this even supported in CosmosDB?
EDIT: Trying to add this index with Robo 3T silently fails, with no error message whatsoever. The index is simply not added. Nice!
(Please don't ask about the strange database schema. It is like it is for a reason, and believe me, I, too, would like to burn it all down and replace it with something else ... I am open for suggestions for alternative queries, though)
This was probably a server-side problem. It seemed wrong in the first place (error status returned as part of the query result), and it has disappeared after a couple of weeks without me changing anything.