Context:
Spring Boot (starter): 2.7.5
Spring Data MongoDB (starter): 2.7
Java version: 17
TLDR
I'd like to generate an aggregation step like this (tested with MongoCompass and works):
{ // "$match" omitted
"value.timestampWithoutTimezoneValue.value" : {
$gt : ISODate('Sat Jan 14 11:29:29 CET 2023')
}
}
but this is generated when I use MongoTemplate instead:
{
"$match":{
"value.timestampWithoutTimezonevalue.value":{
"$gt":{
"$date":"2023-01-14T10:29:29.499Z"
}
}
}
}
I can't really find the reason for this and I get zero results.
Debug details
This is where I generate the Criteria:
case GREATER_THAN -> {
// LocalDateTime: 2023-01-14T11:29:29.499999999
Date out = Date.from(((LocalDateTime) filter.getValue()).atZone(ZoneId.of("UTC")).toInstant()); // out = Sat Jan 14 12:29:29 CET 2023 (I assume it's +0)
yield Criteria.where("value.timestampWithoutTimezonevalue.value").gt(out); // See below
}
EDIT: I noticed that the conversion to Date caused a +1h instead of a +0h, but it's not relevant for this thread's sake. Keep reading and you'll understand.
This is the aggregation pipeline that I submit to MongoTemplate (I omitted the rest because the rest works as intended):
{
...
"pipeline":[
...
{
"$addFields":{
"value.timestampWithoutTimezoneValue.value":{
"$toDate":"$value.timestampWithoutTimezoneValue.value"
}
}
},
{
"$match":{
"value.timestampWithoutTimezonevalue.value":{
"$gt":{
"$date":"2023-01-14T11:29:29.499Z"
}
}
}
}
...
],
...
}
Note that:
Dates are stored in documents as Strings, e.g. "2023-01-07T12:30:30.500", therefore
I need to convert the string to a Date object before $matching
(Note that I'd rather work with Date objects because I might need to run more complex queries in future)
For completion's sake I share the small testing dataset I'm using (only the relevant field):
[{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-07T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-08T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-09T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-10T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-11T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-12T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-13T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-14T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-15T12:30:30.500"
}
}
},{
"value": {
"timestampWithoutTimezoneValue": {
"value": "2023-01-16T12:30:30.500"
}
}
}]
Expectation of the query result:
Return documents with dates:
"2023-01-14T12:30:30.500" (this should be discarded considering my +1h bug)
"2023-01-15T12:30:30.500"
"2023-01-16T12:30:30.500"
Actual Result: Zero results
Conclusions:
This is one of many attempts by the way... I tried to:
Querying by string without converting to Date
Converting string dates to Longs ($toLong) instead of Date objects and querying by timestamp
...
None of the above worked and my impression is that my code is ok. The problem I'm facing is that my aggregation pipeline isn't interpreted the way I expect to (structure-wise) and I can't find a way to make it work out of MongoCompass.
Related
Only articles that contain the EmailMarketing tag are needed.
I'm probably doing the wrong search on the tag, since it's an array of values, not a single object, but I don't know how to do it right, I'm just learning graphql. Any help would be appreciated
query:
query {
enArticles {
title
previewText
tags(where: {name: "EmailMarketing"}){
name
}
}
}
result:
{
"data": {
"enArticles": [
{
"title": "title1",
"previewText": "previewText1",
"tags": [
{
"name": "EmailMarketing"
},
{
"name": "Personalization"
},
{
"name": "Advertising_campaign"
}
]
},
{
"title": "title2",
"previewText": "previewText2",
"tags": [
{
"name": "Marketing_strategy"
},
{
"name": "Marketing"
},
{
"name": "Marketing_campaign"
}
]
},
{
"title": "article 12",
"previewText": "article12",
"tags": []
}
]
}
}
I believe you first need to have coded an equality operator within your GraphQL schema. There's a good explanation of that here.
Once you add an equality operator - say, for example _eq - you can use it something like this:
query {
enArticles {
title
previewText
tags(where: {name: {_eq: "EmailMarketing"}}){
name
}
}
}
Specifically, you would need to create a filter and resolver.
The example here may help.
I'm new to GraphQL and got stuck in a query. Well, this is sample GQL that returns every record in database:
{
viewer {
savingsAccount {
id
feed {
id
__typename
title
detail
postDate
... on TransferInEvent {
amount
originAccount {
name
}
}
... on TransferOutEvent {
amount
destinationAccount {
name
}
}
... on TransferOutReversalEvent {
amount
}
... on BillPaymentEvent {
amount
}
... on DebitPurchaseEvent {
amount
}
... on BarcodePaymentEvent {
amount
}
... on DebitWithdrawalFeeEvent {
amount
}
... on DebitWithdrawalEvent {
amount
}
}
}
}
}
Here is sample return:
{
"data": {
"viewer": {
"savingsAccount": {
"id": "5c8fe258-34fd-4bdc-bfb6-761bc78435df",
"feed": [{
"id": "5fcd6040-cf19-4dbf-be25-47d2f1a7a29b",
"__typename": "DebitPurchaseEvent",
"title": "Test",
"detail": "Test $$",
"postDate": "2020-12-06",
"amount": 59.7
}, {
"id": "5fcd5bbd-fc70-4d87-944d-d0a186559289",
"__typename": "DebitPurchaseEvent",
"title": "Test",
"detail": "Test $$",
"postDate": "2020-12-06",
"amount": 30.0
}
}
}
}
}
How do I apply filter to return some specific postDate? I mean, after, before, etc. This attribute is stored as string but I believe it is possible to do some convertion.
Thanks in advance!
Aggregation aggregation = newAggregation(
match(Criteria.where("moment").gte(from).lte(to)),
project("pass", "carrier", "route", "iso").and("iso").as("country")
.and("$moment").plus(14400000).as("shifted"),
project("shifted").and(DateOperators.DayOfMonth.dayOfMonth("$moment")).previousOperation(),
.andExpression("$moment").dateAsFormattedString("%Y-%m-%d").as("date"),
group("pass", "carrier", "route", "country","date").count().as("total"),
sort(Sort.Direction.DESC, "pass","total")
).withOptions(newAggregationOptions().
allowDiskUse(true).build());
I am trying to do this query in java (mongodb and spring boot) that works in console (the bottom one works fine) but i failed to pass the correct date shifted already (called shifted) to the DateOperators.DayOfMonth. I get projection field must not be null so I think i am using wrong previousOperation(). How should i properly use this previousOperation? or how can i correctly shifted the date i need? thank you very much in advance.
db.billing.aggregate(
[
{
$match: { "moment": { "$gte": ISODate("2020-11-29T00:00:00Z"), "$lt": ISODate("2020-11-29T23:59:59Z")}}
},
{
$project: { "pass" :1, "carrier": 1, "moment" : { $subtract: ["$moment", 14400000 ] } }
},
{
$group: { "_id": {"pass": "$pass","carrier": "$carrier", "day": { "$dayOfMonth": "$moment"},"total": { "$sum": 1 }}}
},
{
$sort: {"_id.day":1}
}
]
)
I have the following data:
{
"_id": ObjectID("5e2fa881c3a1a70006c5743c"),
"name": "Some name",
"policies": [
{
"cId": "dasefa-2738-4cf0-90e0d568",
"weight": 12
},
{
"cId": "c640ad67dasd0-92f981583568",
"weight": 50
}
]
}
I'm able to query this with Spring Mongo fine, however I want to be able to order the policies by weight
At the moment I get my results fine with:
return mongoTemplate.find(query, CArea::class.java)
However say I make the following aggregations:
val unwind = Aggregation.unwind("policies")
val sort = Aggregation.sort(Sort.Direction.DESC,"policies.weight")
How can I go and actually apply those to the returned results above? I was hoping that the dot annotation would do the job in my query however didnt do anything e.g. Query().with(Sort.by(options.sortDirection, "policies.weight"))
Any help appreciated.
Thanks.
I am not familier with Spring Mongo, but I guess you can convert the following aggregation to spring code.
db.collection.aggregate([
{
$unwind: "$policies"
},
{
$sort: {
"policies.weight": -1
}
},
{
$group: {
_id: "$_id",
"policies": {
"$push": "$policies"
},
parentFields: {
$first: "$$ROOT"
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$parentFields",
{
policies: "$policies"
}
]
}
}
}
])
This will result:
[
{
"_id": "5e2fa881c3a1a70006c5743c",
"name": "Some name",
"policies": [
{
"cId": "c640ad67dasd0-92f981583568",
"weight": 50
},
{
"cId": "dasefa-2738-4cf0-90e0d568",
"weight": 12
}
]
}
]
Playground
I'm trying to figure out how to query a single user from graphql schema by id. I'm using the graphiql tool and I'm able to get all Users.
{
allPrismicUsers {
edges {
node {
id
data {
name
}
}
}
}
}
Outputs :
{
"data": {
"allPrismicUsers”: {
"edges": [
{
"node": {
"id": "Prismic__User__WzKFwywAABmiZk_4",
"data": {
"name": “John Doe”
}
}
},
{
"node": {
"id": "Prismic__User__WzKDZywAABmiZkYp",
"data": {
"name": “Jane Doe“
}
}
},
{
"node": {
"id": "Prismic__User__WzKGDiwAAJSiZlFL",
"data": {
"name": “Cat Doe”
}
}
}
]
}
}
}
I also have prismicUser() on the schema
query {
prismicUser {
id
data {
name
}
}
}
Output:
{
"data": {
"prismicUser": {
"id": "Prismic__User__WzKGDiwAAJSiZlFL",
"data": {
"name": "Cat Doe"
}
}
}
}
I'm trying to query a user based on a specific id but not sure if I'm querying the wrong way.
I tried this.
query {
prismicLocation(id: "Prismic__User__WzKDZywAABmiZkYp") {
data {
name
}
}
}
I get an error
{ "errors": [
{
"message": "Argument \"id\" has invalid value \"Prismic__User__WzKDZywAABmiZkYp\".\nExpected
\"prismicUserIdQueryString_2\", found not an object.",
"users": [
{
"line": 25,
"column": 23
}
]
} ] }
How can I call a specific user based on their id ?
According to the Gatsby GraphQL reference, Gatsby allows you to filter results by any field in GraphQL (using operators such as eq, ne, etc.)
The gatsby-source-prismic plugin provides a field called prismicId (i.e. W1syKSIAAAzdN1Jg).
Here is an example query:
{
prismicUser(prismicId:{eq:"WzKDZywAABmiZkYp"}) {
data {
name
}
}
}
But you can also query by id:
prismicUser(id:{eq:"Prismic__User__WzKDZywAABmiZkYp"})