Invalid Query :(

Hi I get the following exception, I’d like to understand why.

`The query you sent was invalid. Probably a filter or ordering specification is not applicable to the type of a field.[
  {
    "name": "unknown",
    "path": [
      "fields",
      "beverage",
      "da-DK",
      "slug"
    ],
    "details": "The path \"fields.beverage.da-DK.slug\" is not recognized"
  }`

I call the ContentFul Client like this

var builder = QueryBuilder<CfRating>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

            var entries = await _client.GetEntries(builder);

My CfRating class looks like this

[JsonObject(Title = "Rating")]
public class CfRating : ContentfulBaseType
{
    [JsonProperty(PropertyName = "title")]
    public string Title { get; set; }

    [JsonProperty(PropertyName = "userRating")]
    public int UserRating { get; set; }

    [JsonProperty(PropertyName = "priceGuess")]
    public decimal PriceGuess { get; set; }

    [JsonProperty(PropertyName = "beverage")]
    public CfBeverage Beverage { get; set; }

    [JsonProperty(PropertyName = "user")]
    public CfUser User { get; set; }
}

And CfBeverage

[JsonObject(Title = "Beverage")]
public class CfBeverage : ContentfulBaseType
{
    [JsonProperty(PropertyName = "title")]
    public string Title { get; set; }

    [JsonProperty(PropertyName = "slug")]
    public string Slug { get; set; }

    [JsonProperty(PropertyName = "type")]
    public CfBeverageType Type { get; set; }
    .
    .
    .

Thanks :slight_smile:

Hi Terkel

The code looks good, but I wonder where the da-DK part of your query comes from in your query, but this might just be implicitly added by the API.

I think the problem here originates from you trying to search on the value of a reference field, but not specifiying the content type of that reference. You can read more about that here: https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/search-on-references

I think if you add this to your query builder everything should work (added some properties that I just assume exist):

var builder = QueryBuilder<CfRating>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.SystemProperties.ContentType.Id, Constants.Contentful.TypeIds.BeveregeContentTypeId)
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

            var entries = await _client.GetEntries(builder);

Hi Robert
Thank you for the quick reply.

I suspect the ´da-DK’-part stems from my changing locales in the space. I changed from english to danish.
I doublechecked that none of the fields in Fields-array on BeverageType has localized-property set to true.

I tried your suggestion, but to no avail :frowning: I got the exact same error message.
Only difference is I “dotted” one more step into the ContentType.SystemProperties to find Id.
I also tried

var builder = QueryBuilder<CfRating>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.sys.ContentType.Name, "Beverage")
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

I got the same error.

If I, however, first query to get the beverage

var beverageBuilder = QueryBuilder<CfBeverage>
            .New.Include(3)
            .ContentTypeIs(Constants.Contentful.TypeIds.BeverageId)
            .FieldEquals(f => f.Slug, beverageSlug);

And the use that beverage-id in query, like this

var builder = QueryBuilder<CfRating>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.sys.Id, beverage.sys.Id);

I get the expected result.
So I suspect something in my mapping goes bananas.

Perhaps it’s my ContentfulBaseType class???
It looks like this

 public abstract class ContentfulBaseType
{
    [JsonProperty(PropertyName = "sys")]
    public SystemProperties sys { get; set; }
}

Or could it be the [JsonPrroperty]-attributes I’m using??

In your first query, could you try changing from ContentType.Name to ContentType.SystemProperties.Id, something like this:

var builder = QueryBuilder<CfRating>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.sys.ContentType.SystemProperties.Id, "Beverage")
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

I missed the SystemProperties part in my first post :cry:

Sure :slight_smile:

Notice, I’ve renamed Rating to UserFeedback
So if I do:

  var builder = QueryBuilder<CfUserFeedback>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.RatingId)
                .FieldEquals(f => f.Beverage.Sys.ContentType.SystemProperties.Id, "Beverage")
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

I get the same error :frowning:
I also tried “beverage” (not capitalised), as this is the Id in contentful.
I also doubled-checked first line, that I use the correct Id for UserFeedbackId. Even tried .ContentTypeIs("userFeedback")

Still same error.

Should I try the Managementclient instead?

Hmm, I really feel like this should work. Is the id of your beverage content type "Beverage"? Remember it’s case sensitive :slight_smile:

:slight_smile: Yeah I feel the same way :slight_smile:

yes, that’s what I tried to say with: I also tried “beverage” (not capitalised), as this is the Id in contentful.

This is my UserFedback-type

{
"name": "User Feedback",
"description": "A rating and priceguess for a beverage created by a user at an event",
"displayField": "title",
"fields": [
  {
  "id": "title",
  "name": "Title",
  "type": "Symbol",
  "localized": false,
  "required": false,
  "validations": [],
  "disabled": false,
  "omitted": false
},
{
  "id": "beverage",
  "name": "Beverage",
  "type": "Link",
  "localized": false,
  "required": true,
  "validations": [
    {
      "linkContentType": [
        "beverage"
      ],
      "message": "Beverage must be chosen"
    }
  ],
  "disabled": false,
  "omitted": false,
  "linkType": "Entry"
 },
 {
  "id": "user",
  "name": "User",
  "type": "Link",
  "localized": false,
  "required": true,
  "validations": [
    {
      "linkContentType": [
        "user"
      ],
      "message": "User must be selected"
    }
  ],
  "disabled": false,
  "omitted": false,
  "linkType": "Entry"
},
{
  "id": "rating",
  "name": "Rating",
  "type": "Integer",
  "localized": false,
  "required": false,
  "validations": [],
  "disabled": false,
  "omitted": false
},
{
  "id": "priceGuess",
  "name": "Price Guess",
  "type": "Number",
  "localized": false,
  "required": false,
  "validations": [
    {
      "range": {
        "min": 0
      },
      "message": "Must be grater than zero"
    }
   ],
   "disabled": false,
  "omitted": false
 }
],
"sys": {
"space": {
  "sys": {
    "type": "Link",
    "linkType": "Space",
    "id": "wti12zckuuby"
  }
},
"id": "userFeedback",
"type": "ContentType",
"createdAt": "2018-09-07T08:28:09.384Z",
"updatedAt": "2018-09-07T09:00:12.874Z",
"environment": {
  "sys": {
    "id": "master",
    "type": "Link",
    "linkType": "Environment"
  }
},
"createdBy": {
  "sys": {
    "type": "Link",
    "linkType": "User",
    "id": "6qbFBQBNtF7rXSx5YSRiuK"
  }
},
"updatedBy": {
  "sys": {
    "type": "Link",
    "linkType": "User",
    "id": "6qbFBQBNtF7rXSx5YSRiuK"
  }
},
"publishedCounter": 2,
"version": 4,
"publishedBy": {
  "sys": {
    "type": "Link",
    "linkType": "User",
    "id": "6qbFBQBNtF7rXSx5YSRiuK"
  }
},
"publishedVersion": 3,
"firstPublishedAt": "2018-09-07T08:28:09.833Z",
"publishedAt": "2018-09-07T09:00:12.874Z"
}
}

I also did builder-build() to get the query-string. It said: "?include=3&content_type=userFeedback&fields.beverage.slug=carbernet-sauvignon"
for this query:

var builder = QueryBuilder<CfUserFeedback>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

I’m gonna try quering for a Entry<dynamic> to try and elimate my classes as the issue

Is this not interesting:
Fields are null
entries.Items has 1 entry
There is only one entry in contentful.

So why can’t we map the damn thing?

OK that query looks good, and should fail since you haven’t specified the content type for beverage. However if you build this one:

var builder = QueryBuilder
.New.Include(3)
.ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
.FieldEquals(f => f.Beverage.Sys.ContentType.SystemProperties.Id, “beverage”)
.FieldEquals(f => f.Beverage.Slug, beverageSlug);

What is the resulting string?

If you take the resulting string and hit the API directly, do you get the same error?

http://cdn.contentful.com/spaces/{YourSpaceID}/entries/{YourQueryString}&access_token={YourAccessToken}

Entry<dynamic> is no longer used for the delivery API, if you wanna try without your classes, just use dynamic directly. This is probably why fields is null in the image above.

OK, so this query

var builder = QueryBuilder<CfUserFeedback>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
                .FieldEquals(f => f.Beverage.Sys.ContentType.SystemProperties.Id, "beverage")
                .FieldEquals(f => f.Beverage.Slug, beverageSlug);

resultet in this querystring: ?include=3&content_type=userFeedback&fields.beverage.sys.contentType.sys.id=beverage&fields.beverage.slug=carbernet-sauvignon

Notice I added my type (<cfUserFeedback>) to querybuilder; I assume this is irrelevant.

If I then hit the API Directly:

Same error :frowning:

“requestId”: “b05dd6c545aa5bd372155e279bcca115”

Oh, I see what’s going wrong now. If you try this querystring:

include=3&content_type=userFeedback&fields.beverage.sys.contentType.sys.id=beverage&fields.beverage.fields.slug=carbernet-sauvignon

This is an inconsistency in the SDK, I think you can update your QueryBuilder like this:

var builder = QueryBuilder
.New.Include(3)
.ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
.FieldEquals(“fields.beverage.fields.slug”, “beverage”)
.FieldEquals(f => f.Beverage.Slug, beverageSlug);

I’ll look into improving the QueryBuilder to correctly add fields for nested references as well.

Then this happens: :sunny:
2018-09-07_13h50_01

YAY!!! Thank you!!!

Tweaking your query a bit, a was able to not get an error.

var builder = QueryBuilder<CfUserFeedback>
                .New.Include(3)
                .ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
                .FieldEquals(f => f.Beverage.Sys.ContentType.SystemProperties.Id, Constants.Contentful.TypeIds.BeverageId)
                .FieldEquals("fields.beverage.fields.slug", beverageSlug);

Am I correct in assuming that the reason I need to provide the ContentType-Id of the referenced type is because the API cannot resolve the type, when I use a string instead of a lambda i FieldEquals??

Do you have an ETA on a fix??

And again; thank you for your help

Great!

Yes, that is correct, you need to provide the content type id if you want to filter by sub-reference properties. However, the SDK should of course not force you to add the .fields, but they should just be resolved. Looking into this now, hopefully a fix out shortly.

Awesome.

I’ll be looking forward. Have a great weekend :+1:

Hmm, turns out it’s not that simple… I need to evalutate the memberexpression (f.Beverage.Slug in this case) and make sure I inject fields if I get to Beverage so that it turns into fields.beverage.fields.slug, the problem here is that I can’t be sure that you want every type of object to add fields. You could have objects that are not content types, for example JSON object fields, location etc.

I’m thinking adding an attribute that you can add to classes that you don’t want the querybuilder to add fields for would be the best solution… You could also do it the other way around and add an attribute to any class that you want the querybuilder to add fields for. Not sure which would be more beneficial in this case.

I am a n00b here, but couldn’t you just add the extra fields if type == link && linkType == Entry ???
I don’t know how the Location of json-type are serialised or structured.

Yeah, if I had that information I surely could :smile: but we come from the other side here. I just have your c# expression and need to turn it into a querystring. I have no real way to know if your Beverage class represents a content type or just a JSON field or something else…

Thinking about it a bit more I think I will have to add an attribute that you put on your class that specifies that you want the fields part added for a querystring involving that particular class as a reference. Otherwise I would change existing behaviour and that is probably best avoided for a small fix like this.

There should now be an updated package, version 3.3.5, available on NuGet. If you update to that version and add a simple attribute to your Beverage property, you should be able to use the strongly typed version of the querybuilder:

[JsonProperty(PropertyName = "beverage")]
[QueryField]
public CfBeverage Beverage { get; set; }

and

var builder = QueryBuilder<CfUserFeedback>
            .New.Include(3)
            .ContentTypeIs(Constants.Contentful.TypeIds.UserFeedbackId)
            .FieldEquals(f => f.Beverage.Sys.ContentType.SystemProperties.Id, Constants.Contentful.TypeIds.BeverageId)
            .FieldEquals(f => f.Beverage.Slug, beverageSlug);

That’s awesome dude.
Updated and confirmed!!!
giphy

1 Like