How to use ReQL filter and match command on arrays - rethinkdb

I have a table in rethinkdb where each row has following structure -
{
'name':'clustername',
'services':[
{
'name':'service1'
},
{
'name':'service2'
}
]
}
I am running a query to filter service2 object like this
r.table('clusters').filter({"name": "clustername"})
.pluck('services').filter((service) => {
return service("name").match('service2')
})
But this is not returning anything: No results were returned for this query
Can anyone tell why this is happening?

pluck returns sequence, so this query:
r.table('clusters').filter({"name": "clustername"}).pluck('services')
will return:
{
"services": [
{
"name": "service1"
} ,
{
"name": "service2"
}
]
}
You need get services field from it, it will return array with services field of items found by filter.
And after that you need to use your second filter on each item by using map.
So, correct query:
r.table('clusters').filter({"name": "clustername"}).pluck('services')("services").map(item => {
return item.filter(service => {
return service("name").match("service2");
});
})

Related

GraphQL filter by multiple values on nested object

I have a GraphQL API and want to filter the results based on the nested tag object. The object looks like this:
{
name
...
tags [
{
name
},
{
name
},
...
]
}
I now want to get all documents that have both tags, a tag with the name "invoice" AND a tag with the name "open". How would I do that?
I already tried doing it like this:
query {
documents (
where: { tags: { some: { name: { and: { in: [ "invoice", "open" ] } } } } }
) {
nodes {
name
tags {
name
}
}
}
}
and some other stuff, but I can't seem to get it to work.
Thanks in advance :)
I believe that you will implement that on the Backend, because the GraphQL is only a descriptive way to do "Queries and Mutations"
😁

Dynamically create pages with Gatsby based on many Contentful references

I am currently using Gatsby's collection routes API to create pages for a simple blog with data coming from Contentful.
For example, creating a page for each blogpost category :
-- src/pages/categories/{contentfulBlogPost.category}.js
export const query = graphql`
query categoriesQuery($category: String = "") {
allContentfulBlogPost(filter: { category: { eq: $category } }) {
edges {
node {
title
category
description {
description
}
...
}
}
}
}
...
[React component mapping all blogposts from each category in a list]
...
This is working fine.
But now I would like to have multiple categories per blogpost, so I switched to Contentful's references, many content-type, which allows to have multiple entries for a field :
Now the result of my graphQL query on field category2 is an array of different categories for each blogpost :
Query :
query categoriesQuery {
allContentfulBlogPost {
edges {
node {
category2 {
id
name
slug
}
}
}
}
}
Output :
{
"data": {
"allContentfulBlogPost": {
"edges": [
{
"node": {
"category2": [
{
"id": "75b89e48-a8c9-54fd-9742-cdf70c416b0e",
"name": "Test",
"slug": "test"
},
{
"id": "568r9e48-t1i8-sx4t8-9742-cdf70c4ed789vtu",
"name": "Test2",
"slug": "test-2"
}
]
}
},
{
"node": {
"category2": [
{
"id": "75b89e48-a8c9-54fd-9742-cdf70c416b0e",
"name": "Test",
"slug": "test"
}
]
}
},
...
Now that categories are inside an array, I don't know how to :
write a query variable to filter categories names ;
use the slug field as a route to dynamically create the page.
For blogposts authors I was doing :
query authorsQuery($author__slug: String = "") {
allContentfulBlogPost(filter: { author: { slug: { eq: $author__slug } } }) {
edges {
node {
id
author {
slug
name
}
...
}
...
}
And creating pages with src/pages/authors/{contentfulBlogPost.author__slug}.js
I guess I'll have to use the createPages API instead.
You can achieve the result using the Filesystem API, something like this may work:
src/pages/category/{contentfulBlogPost.category2__name}.js
In this case, it seems that this approach may lead to some caveats, since you may potentially create duplicated pages with the same URL (slug) because the posts can contain multiple and repeated categories.
However, I think it's more succinct to use the createPages API as you said, keeping in mind that you will need to treat the categories to avoid duplicities because they are in a one-to-many relationship.
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
allContentfulBlogPost {
edges {
node {
category2 {
id
name
slug
}
}
}
}
}
`)
let categories= { slugs: [], names: [] };
result.data.allContentfulBlogPost.edges.map(({node}))=> {
let { name, slug } = node.category2;
// make some checks if needed here
categories.slugs.push(slug);
categories.names.push(name);
return new Set(categories.slugs) && new Set(categories.names);
});
categories.slugs.forEach((category, index) => {
let name = categories.names[index];
createPage({
path: `category/${category}`,
component: path.resolve(`./src/templates/your-category-template.js`),
context: {
name
}
});
});
}
The code's quite self-explanatory. Basically you are defining an empty object (categories) that contains two arrays, slugs and names:
let categories= { slugs: [], names: [] };
After that, you only need to loop through the result of the query (result) and push the field values (name, slug, and others if needed) to the previous array, making the needed checks if you want (to avoid pushing empty values, or that matches some regular expression, etc) and return a new Set to remove the duplicates.
Then, you only need to loop through the slugs to create pages using createPage API and pass the needed data via context:
context: {
name
}
Because of redundancy, this is the same than doing:
context: {
name: name
}
So, in your template, you will get the name in pageContext props. Replace it with the slug if needed, depending on your situation and your use case, the approach is exactly the same.

Is it possible to filter a collection based on a collection field on the content type in graphql & contentful

This might be impossible in graphql/contentful or introduce too much complexity but I'm trying to query a collection and filter on a collection field, something like the following...
query {
eventCollection(
where: {
OR: [
{ categoryCollection: { key: "fashion" } }
]
}
) {
items {
slug
}
}
My back up plan is to query all the events and filter in the client but I thought it would be possible to do the above.
Contentful DevRel here. 👋
Currently, that's not possible. But what you can do is flip the query around and filter on the categoryCollection and then use linkedFrom to request the items linking to it.
query {
categoryCollection(where: {
key: "fashion
}) {
items {
title
linkedFrom {
eventCollection {
items {
slug
}
}
}
}
}
}

GraphQL disable filtering if filter variable is empty

I have a Gatsby GraphQL query for a list of posts ordered by date and filtered by category.
{
posts: allContentfulPost(
sort: {fields: [date], order: DESC},
filter: {category: {slug: {eq: $slug}}}
) {
edges {
node {
title {
title
}
date
}
}
}
}
Right now when $slug is the empty string "", I get
{
"data": {
"posts": null
}
}
Is there a way to get all posts instead?
You can use the regex filter to your advantage. If you pass an empty expression, then all posts will be returned because everything will match.
query Posts($slugRegex: String = "//"){
posts: allContentfulPost(
sort: {fields: [date], order: DESC},
filter: {category: {slug: {eq: $slugRegex}}}
) {
# Rest of the query.
}
}
By default, all posts will be returned (the $slugRegex is an empty regex if nothing was passed). When the $slugRegex becomes a meaningful expression, then only matching posts will show up.
As for passing the value, I'm assuming you're using gatsby-node.js to create pages. In that case, it's as simple as that:
// gatsby-node.js
exports.createPages = async ({ actions }) => {
const { createPage } = actions
// Create a page with only "some-slug" posts.
createPage({
// ...
context: {
slugRegex: "/some-slug/"
}
})
// Create a page with all posts.
createPage({
// ...
context: {
// Nothing here. Or at least no `slugRegex`.
}
})
}
It's not possible with this query, even #skip/#include directives won't help because you can't apply them on input fields.
I would suggest to either adjust the server side logic so that null in the 'eq' field will ignore this filter or either to edit the query being sent (less favorable imo).
It seems that the graphql schema that you work against lacks the filtering support you need..
If anyone requires a solution for other systems than Gatsby this can be accomplished using #skip and #include.
fragment EventSearchResult on EventsConnection {
edges {
cursor
node {
id
name
}
}
totalCount
}
query Events($organizationId: UUID!, $isSearch: Boolean!, $search: String!) {
events(condition: { organizationId: $organizationId }, first: 100)
#skip(if: $isSearch) {
...EventSearchResult
}
eventsSearch: events(
condition: { organizationId: $organizationId }
filter: { name: { likeInsensitive: $search } }
first: 100
) #include(if: $isSearch) {
...EventSearchResult
}
}
Then in your client code you would provide search and isSearch to the query and get your events like:
const events = data.eventsSearch || data.events

ElasticSearch query for items not in given array

I am trying to write a part of a query to filter out any items with a type as "group" and that have a group id that isn't in a given array of ids. I started writing a bool query with a must and must_not but I was getting tripped up on how to write "id not in the given array.
EDIT:
I am actually converting an outdated query using "and" and "not" to be ES 5.5 compatible. Here is the old query that worked.
:and => [
{
term: {
type: 'group'
}
},
{
:not => {
terms: {
group_id: group_ids
}
}
},
{
:not => {
terms: {
user_id: user_ids
}
}
}
]
group_ids and user_ids are arrays.
You probably have not analyzed the arrays with the IDs. You can use a Bool query with a filter clause, and then within that filter start a new bool query with a mustNot clause and within that clause add a terms query with your IDs.
bool: {
must: {
term: {
kind: 'group'
}
},
must_not: [
{
terms: {
group_id: group_ids
}
},
{
terms: {
user_id: user_ids
}
}
]
}

Resources