Filter an array of dates (datetime) with GROQ (sanity) (React App) - sanity

I have a list of movies that could be shown more than once. I decided to provide a user with an option to select multiple dates for a single movie (sanity studio interface).
The schema for movies is as follows:
export default {
name: 'movie',
title: 'Movie',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
name: 'dates',
title: 'Dates',
type: 'array',
of: [
{
type: 'datetime',
options: {
dateFormat: 'YYYY-MM-DD',
timeFormat: 'HH:mm',
timeStep: 15,
calendarTodayLabel: 'Today'
}
}
]
},
{
name: 'poster',
title: 'Poster',
type: 'image',
options: {
hotspot: true
}
},
{
name: 'body',
title: 'Body',
type: 'blockContent'
}
],
preview: {
select: {
title: 'title',
date: 'date',
media: 'poster'
}
}
}
Current query:
const query = groq`*[_type == "movie"]{
title,
dates,
poster,
body
}`
I need to filter the movie that has today's date in the dates array with GROQ
Maybe I'm overcomplicating this and someone will come up with a better way.
The idea is to avoid duplicates in the database (1 movie can be shown 3-6 times). That's the only reason I used an array

The solution for this should be:
const query = '*[_type == "movie" && dates match $today]{title, dates, poster, body}'
const today = new Date().toISOString().split('T')[0]
client.fetch(query, {today}).then(result => {
// movies which are showing today
})
However, there is currently a bug in the string tokenizer which cripples date string matching. In the meantime, I'm afraid your only option is to fetch all movies and filter client side. We're hoping to get this fixed as soon as possible.

Related

vuetable-2 select multiple sort items in same column

I need to filter data, including or excluding, multiple possible options in a column, but I don't know how to do it.
this only shows me a "single" select below the column name, with the possible options, but I can't select multiple of them, and I can't find an option to do that.
I need to filter by 2 rooms or multiple users, but the selection is not multiple, and there is no option to do it.
Now I have this HTML code:
<v-client-table id="messages" style="width:100%;" ref="table_reference" :options="table_options" :columns="table_fields" v-model="messages_array">
</v-client-table>
and this table configuration (messages, and other vars excluded):
const app2 = {
el: "#messages-container",
data() {
return {
table_options: {
filterByColumn: true,
texts: {
filterPlaceholder: ""
},
selectable: {
mode: 'single', // or 'multiple'
only: function(row) {
return true // any condition
},
selectAllMode: 'all',
programmatic: false
},
sortIcon: {
base: 'fa fas',
up: 'fa-long-arrow-alt-up',
down: 'fa-long-arrow-alt-down',
is: 'fa-sort'
},
listColumns: {
user_id: [],
room: [],
status: []
},
sortable: ['user_id', 'status', 'room', "created"],
filterable: ['user_id', "room", "status"],
headings: {
id: '#',
user_id: 'Name',
navigator_info: 'Details',
message: 'Message',
room: 'Room',
status: 'Status',
created: 'Date',
response_to: 'Actions'
}
},
table_fields: ["id", "user_id", "message", "room", "status", "created"],
}
}
};
I think this is a common use of a data table, and there should be a way to do it. I would appreciate your help. Thank you very much in advance!

How to select all documents where one date field is after another date field in FaunaDB

I have a very simple collection with documents that look like this:
{
...
latestEdit: Time(...),
lastPublished: Time(...)
}
I would like to query all documents that have a latestEdit time that's after lastPublished time.
I find FQL to be very different to SQL and I'm finding the transition quite hard.
Any help much appreciated.
Fauna's FQL is not declarative, so you have to construct the appropriate indexes and queries to help you solve problems like this.
Fauna indexes have a feature called "bindings", which allow you to provide a user-defined function that can compute a value based on document values. The binding lets us index the computed value by itself (rather than having to index on latestEdit or lastPublished). Here's what that might look like:
CreateIndex({
name: "edit_after_published",
source: {
collection: Collection("test"),
fields: {
needsPublish: Query(
Lambda(
"doc",
Let(
{
latestEdit: Select(["data", "latestEdit"], Var("doc")),
lastPublished: Select(["data", "lastPublished"], Var("doc")),
},
If(
GT(Var("latestEdit"), Var("lastPublished")),
true,
false
)
)
)
)
}
},
terms: [ { binding: "needsPublish" } ]
})
You can see that we define a binding called needsPublish. The binding uses Let to define named values for the two document fields that we want to compare, and then the If statement checks to see if the latestEdit value is greather than lastPublished value: when it is we return true, otherwise we return false. Then, the binding is used in the index's terms definition, which defines the fields that we want to be able to search on.
I created sample documents in a collection called test, like so:
> Create(Collection("test"), { data: { name: "first", latestEdit: Now(), lastPublished: TimeSubtract(Now(), 1, "day") }})
{
ref: Ref(Collection("test"), "306026106743423488"),
ts: 1628108088190000,
data: {
name: 'first',
latestEdit: Time("2021-08-04T20:14:48.121Z"),
lastPublished: Time("2021-08-03T20:14:48.121Z")
}
}
> Create(Collection("test"), { data: { name: "second", lastPublished: Now(), latestEdit: TimeSubtract(Now(), 1, "day") }})
{
ref: Ref(Collection("test"), "306026150784664064"),
ts: 1628108130150000,
data: {
name: 'second',
lastPublished: Time("2021-08-04T20:15:30.148Z"),
latestEdit: Time("2021-08-03T20:15:30.148Z")
}
}
The first document subtracts one day from lastPublished and the second document subtracts one day from latestEdit, to test both conditions of the binding.
Then we can query for all documents where needsPublish results in true:
> Map(Paginate(Match(Index("edit_after_published"), true)), Lambda("X", Get(Var("X"))))
{
data: [
{
ref: Ref(Collection("test"), "306026106743423488"),
ts: 1628108088190000,
data: {
name: 'first',
latestEdit: Time("2021-08-04T20:14:48.121Z"),
lastPublished: Time("2021-08-03T20:14:48.121Z")
}
}
]
}
And we can also query for all documents where needsPublish is false:
> Map(Paginate(Match(Index("edit_after_published"), false)), Lambda("X", Get(Var("X"))))
{
data: [
{
ref: Ref(Collection("test"), "306026150784664064"),
ts: 1628108130150000,
data: {
name: 'second',
lastPublished: Time("2021-08-04T20:15:30.148Z"),
latestEdit: Time("2021-08-03T20:15:30.148Z")
}
}
]
}

How to search for/select by included entity but include all related entities into result set

In my application, I am using sequelize ORM. There are several entities: A Tool can have Tags and Categories.
Now I want to search for all Tools, that have a specific Tag, but I want to include all relating Tags of that tool (not just the specific one). If I now place a where statement into the include, only specified Tags are included into the result set (see [2]). I tried to limit the Tags in the outer where statement (see [1]), but this does not help either.
Example
Tool A has Tags t1, t2 and t3. Now I want to search all Tools that have the Tag t3, but the result set shall contain all three tags.
Expected result:
Tool A
\
- Tag t1
- Tag t2
- Tag t3
db.Tool.scope('published').findAll({
where: { '$tool.tag.name$': filter.tag }, // [1] Does not work
include: [
{
model: db.User,
attributes: ['id', 'username']
},
{
model: db.Tag,
attributes: ['name'],
through: { attributes: [] },
// [2] Would limit the result specified tag
// where: {
// name: {
// [Op.and]: filter.tag
// }
// }
},
{
model: db.Category,
attributes: ['id', 'name', 'views'],
through: { attributes: ['relevance'] },
where: {
id: {
[Op.and]: filter.category
}
}
}
],
where: {
title: {
[Op.like]: `%${filter.term}%`,
}
},
attributes: ['id', 'title', 'description', 'slug', 'docLink', 'vendor', 'vendorLink', 'views', 'status', 'createdAt'],
order: [['title', 'ASC'], [db.Tag, 'name', 'ASC']]
})
I know I could perform this by performing a select via the Tag in the first place (db.Tag.findAll() instead of db.Tool.findAll(); I've already done this elsewhere in my project), but at the same time I also want to be able to filter by another entity (Category) the same way. So the Tool.findAll() should be the starting point.
Any help appreciated!
First off, you have two where clauses in your top-level query:
where: { '$tool.tag.name$': filter.tag }, // [1] Does not work
// ...
where: {
title: {
[Op.like]: `%${filter.term}%`,
}
},
I think your best approach is going to be with a literal subquery in the WHERE clause. Basically we want to find the ids of all of the tools that have the right tag and that contain the filter.term.
The subquery part for the WHERE looks something like...
SELECT ToolId FROM ToolTags WHERE TagId='t2';
Inspired by the subquery solution from this post Sequelize - subquery in where clause
// assuming your join table is named 'ToolTags' in the database--we need the real table name not the model name
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('ToolTags',{
attributes: ['ToolId'],
where: {
TagId: filter.tag
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
db.Tool.scope('published').findAll({
where: {
title: {
[Op.like]: `%${filter.term}%`,
},
id: {
[Op.In]: sequelize.literal(`(${tempSQL})`)
}
},
include: [
{
model: db.User,
attributes: ['id', 'username']
},
{
model: db.Tag,
attributes: ['name'],
through: { attributes: [] },
},
// {
// model: db.Category,
// attributes: ['id', 'name', 'views'],
// through: { attributes: ['relevance'] },
// where: {
// id: {
// [Op.and]: filter.category
// }
// }
// }
],
attributes: ['id', 'title', 'description', 'slug', 'docLink', 'vendor', 'vendorLink', 'views', 'status', 'createdAt'],
order: [['title', 'ASC'], [db.Tag, 'name', 'ASC']]
})
I commented out your category join for now. I think you should try to isolate the solution for the tags before adding more onto the query.

Using rally app lookback API - unable to fetch defects that are tagged

I am using rally lookback API and creating a defect trend chart. I need to filter defects that do not have a tag "xyz".
Using the following:
this.myTrendChart = Ext.create('Rally.ui.chart.Chart', {
storeType: 'Rally.data.lookback.SnapshotStore',
storeConfig: {
find: {
_TypeHierarchy: "Defect",
State: { $lt: "Closed"},
Tags.Name: { $nin: ["xyz"] },
_ProjectHierarchy: projectOid,
_ValidFrom: {$gte: startDateUTC}
}
},
calculatorType: 'Calci',
calculatorConfig: {},
chartConfig: {
chart: {
zoomType: 'x',
type: 'line'
},
title: {
text: 'Defect trend'
},
xAxis: {
type: 'datetime',
minTickInterval: 7
},
yAxis: {
title: {
text: 'Number of Defects'
}
}
}
});
This does not return any data. Need help with the filter for tags.
Tags is a collection of tag-oids so you'll need to find and use the oid of the tag vs the name, at which point it'll just be Tags: { $nin: [oid] }. Caveat: technically, due to how expensive it is, $nin is unsupported (https://rally1.rallydev.com/analytics/doc/#/manual/48e0589f681160fc316a8a4802dc389f)...but it doesn't throw an error so maybe it works anyway.

How do I query for tag names with :find in SnapshotStore store config

I am trying to setup a filter that is similar to a defect view within a Trend chart. The filter in the defect view is:
(State < Closed) AND (Severity <= Major) AND (Tags !contains Not a Stop Ship)
I cannot seem to get the Tags find to work correctly. Any suggestions?
this.myTrendChart = Ext.create('Rally.ui.chart.Chart', {
storeType: 'Rally.data.lookback.SnapshotStore',
storeConfig: {
find: {
_TypeHierarchy: "Defect",
State: {
$lt: "Closed"
},
Severity: {
$lte: "Major"
},
Tags: {
$ne: "Not a Stop Ship"
},
_ProjectHierarchy: ProjectOid
},
hydrate: ["Priority"],
fetch: ["_ValidFrom", "_ValidTo", "ObjectID", "Priority"]
},
calculatorType: 'My.TrendCalc',
calculatorConfig: {},
chartConfig: {
chart: {
zoomType: 'x',
type: 'line'
},
title: {
text: 'Defects over Time'
},
xAxis: {
type: 'datetime',
minTickInterval: 3
},
yAxis: {
title: {
text: 'Number of Defects'
}
}
}
});
Based on reviewing the JSON messages, I figured out the tag needed to be the ObjectId. Once I found this, I replaced "Not a Stop Ship" with the ObjectId value and the filter worked correctly.