MongoDB $addField and $indexOfArray in Spring Data - mongodb

I am trying to implement a custom sort with MongoDB and Spring Data according to Asya Kamsky's post:
List<AggregationOperation> operations = new ArrayList<>();
operations.add(Aggregation.addFields().addField("scorrrz")
.withValueOfExpression("{ \"$indexOfArray\" : [ [\"John\", \"Bill\"], \"$name\" ] }").build());
When I try to execute this, I get:
ERROR a.insurance.misc.ErrorAttributes - /api/v1/insurance/opportunity/all
org.springframework.expression.spel.SpelParseException: Expression [{ "$indexOfArray" : [ ["John", "Bill"], "$name" ] }] #29: EL1043E: Unexpected token. Expected 'rsquare(])' but was 'comma(,)'
Is this not the right syntaxt? How can this be done with Spring Data?

Collection<String> nameList = Arrays.asList("John", "Bill");
Aggregation agg = newAggregation(
addFields()
.addField("scorrrz").withValue(arrayOf(nameList).indexOf("$name"))
.build()
);
The aggregation's projection is an $addFields stage with a $indexOfArray aggregation array operation. This will return a field scorrrz, and it will have index value or -1 when there is no match. This ran okay with Spring Boot v2.3.10 and MongoDB v4.2.8.
The run this aggregation pass the pipeline agg to the MongoTemplate#aggregate method.

If you want to calculate $indexOfArray using the array from the DB document itself, you need the aggregate pipeline to perform the calculation instead of the Java code.
Here is my solution
Aggregation.addFields()
.addField("scorrrz")
.withValueOf(MongoExpression.create(" $indexOfArray : [ [ 'John', 'Bill' ], '$name' ]"))
.build()
This creates the following pipeline stage
{
"$addFields": {
"scorrrz": {
"$indexOfArray": [
[
"John",
"Bill"
],
"$name"
]
}
}
}

Related

Update two fields in same document in MongoDB, where one field is simple update, other field is append to existing array

A document in my MongoDB Collection has two fields which are
lastLongLat - [123.45,11.34] GeoJSON Point format
multipleLongLat - [[12,45],[78,89],[12,54]] GeoJSON MultiPoint format
An array newLongLat from Http Request is in this format : newLongLat = [78.486671,17.385044];
multipleLongLat already has array of arrays.
I need to update two fields as :
update lastLongLat to newLongLat
append newLongLat to existing data in multipleLongLat array at the end.
Document can be filtered by {"productId" : productId}.
I am using Mongoose framework with NodeJS. Please mention an efficient way to perform this operation simultaneously? Thanks in advance.
Simple $set in an aggregation pipeline. You can simply treat the coordinates field as an inner field of an object.
db.collection.update({
"productId": "p1"
},
[
{
$set: {
"lastLongLat": {
type: "Point",
coordinates: [
78.486671,
17.385044
]
},
"multipleLongLat.coordinates": {
"$concatArrays": [
"$multipleLongLat.coordinates",
[
[
78.486671,
17.385044
]
]
]
}
}
}
])
Mongo Playground

Pymongo - Query mongdb for first array elemnet by query of list of values

Given collection:
{
"_id" : "1.1000038",
"recomendation" : [
"1.6739718"
]
}
/* 2 */
{
"_id" : "1.1000069",
"recomendation" : [
"1.9185509",
"1.9051998",
"1.9034279",
"1.8288046",
"1.8152670",
"1.858775",
"1.6224229",
"1.4591674",
"1.3862464",
"1.3427739",
"1.3080062",
"1.3003608",
"1.1694619",
"1.1634683",
"1.1590664",
"1.1524146",
"1.754599",
"1.700837",
"1.763617"
]
}
I need to query the MongoDB for a list of values and get the first element of the list of values
here is the query by mongo syntax
db.getCollection('similar_articles').find({"_id":{$in:["1.1000069","1.1000038"]}})
I don't want to filter it on the python side because it's can be too big.
I didn't find any documentation on it
desire output:
Pandas DataFrame
_id recom
1.1000038 1.6739718
1.1000069 1.9185509
I don't know pymongo so well, but you need this query:
First $match by _ids into the arreay (this is like the find you have).
And later use $project to create the field recom (you can use "recomendation" to overwrite the existing field) and set the value as the first into the array.
db.collection.aggregate([
{
"$match": { "_id": { "$in": [ "1.1000069", "1.1000038" ] } }
},
{
"$project": { "recom": { "$arrayElemAt": [ "$recomendation", 0 ] } }
}
])
Example here
Looking the doumentation it seems you only need to copy and paste this query.

Is there a way get documents and the associated facets in one query with MongoDb?

I want to run some query, get first X documents and the facet data on the full data set.
Is it possible in one query or I must do two queries for that? (one for documents and one for facet data)
For example, unifying the following two, to one query:
db.mycollection.find({tenant:"tenant1", class: "myclass"}).limit(20)
db.mycollection.aggregate( [ {$match: {tenant:"tenant1", class: "myclass"}},
{$facet: { "typeFacet": [{$sortByCount: "$type"}]}])
The following aggregation will get the first 20 (as specified by the $limit) documents as the"xDocs" facet result, for the the documents that match filter in the $match stage. The "typeFacet" facet will apply the $sortByCount.
The $facet pipeline stage allows run multiple facet queries in parallel on the same set of documents (in this case all the documents in the collection).
db.collection.aggregate( [
{ $facet: {
xDocs: [
{ $match: { tenant: "tenant1", class: "myclass" } },
{ $limit: 20 }
],
typeFacet: [
{ $sortByCount: "$type" }
]
} }
] )

Spring Mongo aggregation query with concatenating two arrays and project the result

I have a MongoDB aggregation query, I need the Spring boot mongo aggregation object example for the Following query.
db.case.aggregate([
{ $project: { item: { $concatArrays: [ "$workApproval.partItems", "$warrantyClaims.items.items" ] } } }
,{ $unwind : "$item"}
])
I am stuck on the concatArray portion, I am not sure how to write the above query in Spring Boot Mongo aggregation, any help is appreciated.
Here you are:
List<AggregationOperation> operations = new ArrayList<>();
operations.add(
Aggregation.project()
.and("workApproval.partItems").concatArrays("warrantyClaims.items.items").as("item")
);
operations.add(Aggregation.unwind("item"));
Aggregation aggregation = Aggregation.newAggregation(operations);

Group by array of document in Spring Mongo Db

How can I group by tagValue in Spring and MongoDb?
MongoDB Query :
db.feed.aggregate([
{ $group: { _id: "$feedTag.tagValue", number: { $sum : 1 } } },
{ $sort: { _id : 1 } }
])
How can I do the same thing in Spring MongoDB, may be using Aggregation method?
Sample document of feed collections:
{
"_id" : ObjectId("556846dd1df42d5d579362fd"),
"feedTag" : [
{
"tagName" : "sentiment",
"tagValue" : "neutral",
"modelName" : "sentiment"
}
],
"createdDate" : "2015-05-28"
}
To group by tagValue, since this is an array field, you need to apply the $unwind pipeline step before the group to split the array so that you can get the actual count:
db.feed.aggregate([
{
"$unwind": "$feedTag"
}
{
"$group": {
"_id": "$feedTag.tagValue",
"number": { "$sum" : 1 }
}
},
{ "$sort": { "_id" : 1 } }
])
The following is the equivalent example in Spring Data MongoDB:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
Aggregation agg = newAggregation(
unwind("feedTag"),
group("feedTag.tagValue").count().as("number"),
sort(ASC, "_id")
);
// Convert the aggregation result into a List
AggregationResults<Feed> results = mongoTemplate.aggregate(agg, "feed", Feed.class);
List<Feed> feedCount = results.getMappedResults();
From the above, a new aggregation object is created via the newAggregation static factory method which is passed a list of aggregation operations that define the aggregation pipeline of your Aggregation.
The firt step uses the unwind operation to generate a new document for each tag within the "feedTag" array.
In the second step the group operation defines a group for each embedded "feedTag.tagValue"-value for which the occurrence count is aggregated via the count aggregation operator.
As the third step, sort the resulting list of feedTag by their tagValue in ascending order via the sort operation.
Finally call the aggregate Method on the MongoTemplate to let MongoDB perform the actual aggregation operation with the created Aggregation as an argument.
Note that the input collection is explicitly specified as the "feed" parameter to the aggregate Method. If the name of the input collection is not specified explicitly, it is derived from the input-class passed as first parameter to the newAggreation Method.