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.
pullByFilteronly accepts one argument. It seems that argument can be anotherBsonfilter which is applied directly to each of the children, or aBsonValuethat will be matched against. Since none of theBsonfilters step into the child documents, you have to create aBsonValue, specifically, a document. I believe this should solve your problem:I would have liked to be able to switch back using
Bsonfilters after getting to the inner document, but it seems that once you're inBsonValues, 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.