Need a CouchDB trick to sort by date and filter by group - view

I have documents with fields 'date' and 'group'. And this is my view:
byDateGroup: {
map: function(doc) {
if (doc.date && doc.group) {
emit([doc.date, doc.group], null);
}
}
}
What would be the equivalent query of this:
select * from docs where group in ("group1", "group2") order by date desc
This simple solution is not coming into my head. :(

Pankaj, switch the order of the key you're emitting to this:
emit([doc.group, doc.date], doc);
Then you can pass in a start key and an end key when querying the view. It might be easier to do a separate query for each group that you want to pull data for. The data will be sorted by date.
I'm on my way out at the moment, but can elaborate more when I get back if it isn't clear.

why not?
function(doc) {
if (doc.date && ["group1", "group2"].indexOf(doc.group) !== -1)) {
emit([doc.date, doc.group], null);
}
}

You need a specific view for this:
byDateGroup1Group2: {
map: function(doc) {
if (doc.date && doc.group && (doc.group === "group1" || doc.group === "group2") {
emit(doc.date, doc);
}
}
}
that you query (presumably in a list function) with query descending=true.

Related

BootstrapVue table : sort by date and by string?

I am quite new to VueJS, and currently using BootstrapVue (latest version, v2.0.0), mostly its b-table feature. I load table items dynamically (from a JSON file), and one of my field (column) is a string, the other is a formatted date (dd/MM/YYYY). I would like be able to sort those dates like other string or number fields.
The doc mention the possibility to create custom sorting function, so I wrote one (as a global function, using moment.js as suggested) :
function sortDate(a, b, key) {
aDate = moment(a[key], 'DD/MM/YYYY')
bDate = moment(b[key], 'DD/MM/YYYY')
if (aDate.isValid && bDate.isValid) {
if (aDate < bDate) {
return -1
}
else if (aDate > bDate) {
return 1
}
else {
return 0
}
}
return null
}
I then integrate it to HTML b-table using the :sort-compare tag :
<b-table id="bh_table" :items="items" :fields="fields" :sort-compare="sortDate"></b-table>
The problem is that the regulat string-sorting is broken, and I am not sure how to fix it ? Should I create a global method that should detect column type, and sort accordingly ?
It seems to be the thing to do here, but I think it is quite counter-intuitive, getting possible duplicates (I have other table that contains number and dates, only dates, etc.)
You are not checking for which key is being sorted on. Also note a and b are the entire row data.
function sortDate(a, b, key) {
if (key !== 'myDateField') {
// `key` is not the field that is a date.
// Let b-table handle the sorting for other columns
// returning null or false will tell b-table to fall back to it's
// internal sort compare routine for fields keys other than `myDateField`
return null // or false
}
aDate = moment(a[key], 'DD/MM/YYYY')
bDate = moment(b[key], 'DD/MM/YYYY')
if (aDate.isValid && bDate.isValid) {
if (aDate < bDate) {
return -1
}
else if (aDate > bDate) {
return 1
}
else {
return 0
}
}
return null
}

How can I do a WpGraphQL query with a where clause?

This works fine
query QryTopics {
topics {
nodes {
name
topicId
count
}
}
}
But I want a filtered result. I'm new to graphql but I see a param on this collection called 'where', after 'first', 'last', 'after' etc... How can I use that? Its type is 'RootTopicsTermArgs' which is likely something autogenerated from my schema. It has fields, one of which is 'childless' of Boolean. What I'm trying to do, is return only topics (a custom taxonomy in Wordpress) which have posts tagged with them. Basically it prevents me from doing this on the client.
data.data.topics.nodes.filter(n => n.count !== null)
Can anyone direct me to a good example of using where args with a collection? I have tried every permutation of syntax I could think of. Inlcuding
topics(where:childless:true)
topics(where: childless: 'true')
topics(where: new RootTopicsTermArgs())
etc...
Obviously those are all wrong.
If a custom taxonomy, such as Topics, is registered to "show_in_graphql" and is part of your Schema you can query using arguments like so:
query Topics {
topics(where: {childless: true}) {
edges {
node {
id
name
}
}
}
}
Additionally, you could use a static query combined with variables, like so:
query Topics($where:RootTopicsTermArgs!) {
topics(where:$where) {
edges {
node {
id
name
}
}
}
}
$variables = {
"where": {
"childless": true
}
};
One thing I would recommend is using a GraphiQL IDE, such as https://github.com/skevy/graphiql-app, which will help with validating your queries by providing hints as you type, and visual indicators of invalid queries.
You can see an example of using arguments to query terms here: https://playground.wpgraphql.com/#/connections-and-arguments

Dexie.js - ordering with more than one index

I am using dexie.js to interface with IndexedDB. I am wondering if it is possible to orderby or sortby using more than one index at once (eg. db.people.orderBy( index1, desc : index2, asc )...
If it is possible, what is the correct syntax?
Either use compound indexes, or use Collection.and().
If you can live with only targeting Chrome, Firefox or Opera, you can use compound indexes. If it must work on Safari, IndexedDBShim, Edge or IE, you cannot use compound indexes today. There's a shim that enables it for IE/Edge though, but it is still in beta, so I would recommend to instead use Collection.and() for those cases.
Let' say you have a form where users can fill in various attributes of friends:
<form>
<input name="name"/>
<input name="age"/>
<input name="shoeSize" />
</form>
Using Collection.and()
First, pick the most probably index to start your search on. In this case, "name" would be a perfect index that wouldn't match so many items, while age or shoeSize would probably match more friends.
Schema:
db.version(X).stores({
friends: "id, name, age, shoeSize"
});
Query:
function prepareQuery () {
// Pick a good index. The picked index will filter out with IndexedDB's built-in keyrange
var query;
if (form.name.value) {
query = db.friends.where('name').equals(form.name.value);
} else if (form.age.value) {
query = db.friends.where('age').equals(parseInt(form.age.value));
} else if (form.shoeSize.value) {
query = db.friends.where('shoeSize').equals(parseInt(form.shoeSize.value));
} else {
query = db.friends.toCollection();
}
// Then manually filter the result. May filter a field that the DB has already filtered out,
// but the time that takes is negligible.
return query.and (function (friend) {
return (
(!form.name.value || friend.name === form.name.value) &&
(!form.age.value || friend.age == form.age.value) &&
(!form.shoeSize.value || friend.shoeSize == form.shoeSize.value));
});
}
// Run the query:
form.onsubmit = function () {
prepareQuery() // Returns a Collection
.limit(25) // Optionally add a limit onto the Collection
.toArray(function (result) { // Execute query
alert (JSON.stringify(result, null, 4));
})
.catch (function (e) {
alert ("Oops: " + e);
});
}
Using compound indexes
As written above, compound indexes code will only work on mozilla- and chromium based browsers.
db.version(x).stores({
friends: "id, name, age, shoeSize," +
"[name+age+shoeSize]," +
"[name+shoeSize]," +
"[name+age]," +
"[age+shoeSize]"
});
The prepareQuery() function when using compound indexes:
function prepareQuery() {
var indexes = []; // Array of Array[index, key]
if (form.name.value)
indexes.push(["name", form.name.value]);
if (form.age.value)
indexes.push(["age", parseInt(form.age.value)]);
if (form.shoeSize.value)
indexes.push(["shoeSize", parseInt(form.shoeSize.value)]);
var index = indexes.map(x => x[0]).join('+'),
keys = indexes.map(x => x[1]);
if (indexes.length === 0) {
// No field filled in. Return unfiltered Collection
return db.friends.toCollection();
} else if (indexes.length === 1) {
// Single field filled in. Use simple index:
return db.friends.where(index).equals(keys[0]);
} else {
// Multiple fields filled in. Use compound index:
return db.friends.where("[" + index + "]").equals(keys);
}
}
// Run the query:
form.onsubmit = function () {
prepareQuery() // Returns a Collection
.limit(25) // Optionally add a limit onto the Collection
.toArray(function (result) { // Execute query
alert (JSON.stringify(result, null, 4));
})
.catch (function (e) {
alert ("Oops: " + e);
});
}
Using arrow functions here to make it more readable. Also, you're targeting chromium or firefox and they support it already.

How can i dynamically Create Criteria Mongodb Spring data mongo Template

I need to dynamically create a criteria but i am having problem how can i build criteria dynamically.
I need exactly the same as in here Build dynamic queries with Spring Data MongoDB Criteria but i am getting an error while i am converting my Criteria list to a toArray as its keep saying that orCriteria does not have support for Criteria[]
here is my effort so far
Here is my query structure
{
"query":{
"where":[{
"or":[
{
"fieldName":"title","fieldValue":"Demo Event NEW YORK IIII22222",
"operator":"equal"
},
{
"fieldName":"createdBy","fieldValue":"system",
"operator":"equal"
}
]
}
]
}
}
and here is my parsing it to create criteria
if(null != eventSearch.getQuery())
{
if(null != eventSearch.getQuery().getWhere() && eventSearch.getQuery().getWhere().size()> 0)
{
for (Where whereClause : eventSearch.getQuery().getWhere()) {
if(null != whereClause.getOr() && whereClause.getOr().size() > 0){
for (Field field: whereClause.getOr()) {
if(field.getOperator().equalsIgnoreCase(QueryOperator.IS))
{
// So i need to append an or Condition to main query for each or object in my query can anyone tell me how can i achieve this?
query.addCriteria(Criteria.where(whereClause.getFieldName()).gte(whereClause.getFieldValue()));
}
}
}
}
}
I need to pass my all where clauses with in or object to orOperator function as a parameter
Criteria c = new Criteria().orOperator(Need to pass my where clauses here);
Better use an ArrayList of Criteria to keep $or criteria as below.
List<Criteria> orCriteriaList = new ArrayList<Criteria>();
for (Field field: whereClause.getOr()) {
if(field.getOperator().equalsIgnoreCase(QueryOperator.IS)){
Criteria c1 = Criteria.where(whereClause.getFieldName()).gte(whereClause.getFieldValue());
orCriteriaList.add(c1);
}
}
Then build the main query from this orCriteriaList as
mainQuery.addCriteria(new Criteria().orOperator(orCriteriaList.toArray(new Criteria[orCriteriaList.size()])));

CouchDB "Join" two documents

I have two documents that looks a bit like so:
Doc
{
_id: AAA,
creator_id: ...,
data: ...
}
DataKey
{
_id: ...,
credits_left: 500,
times_used: 0,
data_id: AAA
}
What I want to do is create a view which would allow me to pass the DataKey id (key=DataKey _id) and get both the information of the DataKey and the Doc.
My attempt:
I first tried embedding the DataKey inside the Doc and used a map function like so:
function (doc)
{
if (doc.type == "Doc")
{
var ids = [];
for (var i in doc.keys)
ids.push(doc.keys[i]._id);
emit(ids, doc);
}
}
But i ran into two problems:
There can be multiple DataKey's per
Doc so using startkey=[idhere...]
and endkey=[idhere..., {}] didn't
work (only worked if the key happend
to be the first one in the array).
All the data keys need to be unique, and I would prefer not making a seperate document like {_id = datakey} to reserve the key.
Does anyone have ideas how I can accomplish this? Let me know if anything is unclear.
-----EDIT-----
I forgot to mention that in my application I do not know what the Doc ID is, so I need to be able to search on the DataKey's ID.
I think what you want is
function (doc)
{
if (doc.type == "Doc")
{
emit([doc._id, 0], doc);
}
if(doc.type == "DataKey")
{
emit([doc.data_id, 1], doc);
}
}
Now, query the view with key=["AAA"] and you will see a list of all docs. The first one will be the real "Doc" document. All the rest will be "DataKey" documents which reference the first doc.
This is a common technique, called CouchDB view collation.

Resources