Distinct Query with Cloudant Connector using Loopback in API Connect/StrongLoop - ibm-cloud

I am trying to get distinct values for a query using Loopback with a Cloudant Connector, but I haven't found anything about this in the documentation.
e.g. I need a query to turn this:
[
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★☆☆"
},
{
rating: "★★★☆☆"
}
]
into this:
[
{
rating: "★★★★★"
},
{
rating: "★★★☆☆"
}
]
I'm using the REST API to query my Products model (above is a filtered view of just the rating field). If there is some sort of filter that I can use without modifying the server that I somehow just missed in the documentation, that would be the best choice.
Is there any way I can add a distinct field like:
/Products?filter[fields][rating]=true?distinct=true
or how can I go about solving this?
Also, I've seen another answer talking about adding a remote method to solve this (something like this for mySQL):
Locations.regions = function (cb) {
var ds = Locations.app.datasources.myDS;
var sql = "SELECT DISTINCT region FROM Locations ORDER BY region"; // here you write your sql query.
ds.connector.execute(sql, [], function (err, regions) {
if (err) {
cb(err, null);
} else {
cb(null, regions);
}
});
};
Locations.remoteMethod(
'regions', {
http: {
path: '/regions',
verb: 'get'
},
returns: {
root: true,
type: 'object'
}
}
);
If this would work, how would I implement it with the Cloudant NoSQL DB connector?
Thanks!

If your documents looked like this:
{
"name": "Star Wars",
"year": 1978,
"rating": "*****"
}
You can create a MapReduce view, which emits doc.rating as the key and uses the build-in _count reducer:
function(doc) {
emit(doc.rating,null);
}
When you query this view with group=true, distinct values of rating will be presented with counts of their occurrence in the data set.

Related

use where query depends on query on prisma

const fictions = await client.fiction.findMany({
where: {
AND: [
{ genre: genres as string },
{ nationality: nationalities as string },
{
keywords: {
some: {
keyword: {
name: keywords?.toString().split(",").join(" | "),
},
},
},
},
],
},
include: { ~~~
},
orderBy: {
userFictionStat: {
total: "asc",
},
},
});
Hi, I'm new to prisma so stuck in createing api pages.
I want to filter my 'fictions' with multiple criteria
('genre' or 'nationality' or 'keywords').
The problem is that when 'genre' or 'nationality' or 'keywords' are 'undefined'(button unclicked), the result becomes 0.(because of the 'AND').
I can't find out how can I filter my fictions with given criteria(with clicked buttons, even if some buttons are unclicked).
Also, I'd like to know how can I sort my fictions using my queries.
(lik if i get query {sorting : totalpoint} I can sory by totalPoint, and if i get {sorting : title} then I can sort by title name.
If anyone could help, I would be very thank you.
If genres can be undefined or false-y (including '' or "") then you can do typeof genres === "string" ? genres : undefined as part of your filter. Same for nationalities. That way you know you're passing a string which has meaningful content OR you are ignoring the filter.

Why I'm I getting an error saving date using graphql > hasura > postgres

I'm using react, apollo, graphql, hasura, postgres as my stack to interact with the database. I think my issue is something small, so I'll just focus on the part that's not working rather than posting the whole code.
Thanks.
Error: GraphQL error: unexpected variables in variableValues: birthday
at new ApolloError (bundle.esm.js:63)
at Object.next (bundle.esm.js:1004)
at notifySubscription (Observable.js:135)
at onNotify (Observable.js:179)
at SubscriptionObserver.next (Observable.js:235)
at bundle.esm.js:866
at Set.forEach (<anonymous>)
at Object.next (bundle.esm.js:866)
at notifySubscription (Observable.js:135)
at onNotify (Observable.js:179)
at SubscriptionObserver.next (Observable.js:235)
at bundle.esm.js:76
variables{ id: 2324324, name: "Fred", birthday: "1991-01-11" }
If i remove birthday the query works.
Here is the function
const onUpdateUser = (options) => {
updateUser({
variables: Object.assign({ id: userId }, options),
optimisticResponse: {
__typename: "mutation_root",
update_users: {
__typename: "users_mutation_response",
affected_rows: 1,
returning: [
{
__typename: "users",
id: userId,
...options,
},
],
},
},
});
};
input {birthday: '1991-01-11'}
So without looking at your graphql query, I think you may be thinking of it a little bit off.
You can't dynamically add non-existent variables to a graphql query. The error is telling you that you are trying to add a variable that doesn't exist in your query
i.e. this with NOT work because you haven't defined birthday.
mutation updateUser(
$userId: Int!
$birthday (UNDEFINED)
) {
rest of query...
}
If you need to add a dynamic amount of variables, you could do something like this.
React Code
const onUpdateUser = (options) => {
updateUser({
variables: {
userId,
userVariables: options
},
optimisticResponse: {
__typename: "mutation_root",
update_users: {
__typename: "users_mutation_response",
affected_rows: 1,
returning: [
{
__typename: "users",
id: userId,
...options,
},
],
},
},
});
};
GraphQL mutation
mutation updateUser(
$userId: Int!
$userVariables: user_set_input!
) {
update_user(
where: { id: { _eq: $userId} }
_set: $userVariables
) {
affected_rows
}
}
https://hasura.io/docs/1.0/graphql/manual/mutations/update.html

Execute an aggregate query inside a mongo function

None of the examples show doing a simple sum inside a function, how do I do an aggregate query from a function?
Basically just trying to store a collection of known queries as a function on Mongo
you can define your queries as functions. Assume below schema of posts in a blog that you can save it as favourite. If you need to increase or decreasefavCount you can perform it as below,
const PostSchema = new Schema(
{
//other necessary fields as title, description of the post..etc
favoriteCount: {
type: Number,
default: 0,
},
},
{ timestamps: true },
);
PostSchema.statics = {
incFavoriteCount(postId) {
return this.findByIdAndUpdate(postId, { $inc: { favoriteCount: 1 } });
},
decFavoriteCount(postId) {
return this.findByIdAndUpdate(postId, { $inc: { favoriteCount: -1 } });
}
};
export default mongoose.model('Post', PostSchema);

Change type of value in collection using update

I am looking for a way, how to update multiple documents in MongoDB. I want to modify similar structure like this one:
{[
"_id": 'mongo_id',
"name": "Name"
]}
to the structure like this, basically just change string attribute to object attribute with string property :
{
"_id": 'mongo_id',
"name": {
"type_1": "Name",
"type_2": ""
}
}
Is there a way how to do it in single mongo query or I have to create some kind of worker for example in node.js?
If you do not have any schemas involved to put constrains on your collections or if you have and name is defined as mixed type (from mongoose types as an example) then you can do whatever you want to any of the properties other than _id.
for example this update will change name to the object you want:
db.getCollection('<collectionName>').update({
_id: "mongo_id")
}, {
name: {
"type_1": "Name",
"type_2": ""
}
})
It looks like the best solution is create little worker to get all documents and update them in collection. I used node.js and mongodb npm package to create worker similar to this one:
var mongo = requiere('mongodb');
mongo.connect(process.env.MONGO_URL, function(err, database) {
if (err) {
throw err;
}
db = database;
db.collection('<collectionName>').find({}).toArray(function(err, array) {
if (err) {
console.log(err);
return process.exit(1);
}
console.log('length:', array.length);
var promises = [];
array.forEach(item => {
promises.push(db.collection('<collectionName>').update(
{
_id: item._id
},
{
'$set': {
'name': {
'type_1': item.name,
'type_2': '',
}
}
}))
});
return Promise.all(promises).then(function() {
console.log('Done');
return process.exit(0);
}).catch(function(err) {
console.log('err:', err);
return process.exit(1);
});
});
});

Waterline: How to perform IN queries if attribute is a collection?

In the docs of waterline it is stated that this is the way to perform a IN query on a model:
Model.find({
name : ['Walter', 'Skyler']
});
And this the way to perform an OR query on a model:
Model.find({
or : [
{ name: 'walter' },
{ occupation: 'teacher' }
]
})
My problem now is that i need a combination of those two, and to make it even more complicated, one of the attributes i have to use is a collection.
So what i tried is this, but it doesn't seem to work:
Product.find({
or : [
{ createdBy: userIds },
{ likes: userIds }
]
})
Note: userIds is an array of id's from a user model.
The (simplified) product model looks likes this:
module.exports = {
attributes: {
name: 'string',
description: 'string',
createdBy: {
model: 'User'
},
brand: {
model: 'Brand',
},
likes: {
collection: 'User',
}
}
}
The query works when I only include createdBy, so it seems to be a problem with the collection attribute.
Is this somehow possible?
Thank you for your input.
UPDATE:
I think this is only possible with native() queries.
The way I understand it something like this should work.
Product.native(function(err, products){
if(err) return res.serverError(err);
products.find({"likes": { $elemMatch: { _id: { $in: userIds}}}}).toArray(function(err, results){
if (err){
console.log('ERROR', err);
}
else {
console.log("found products: " + results.length);
console.log(results);
return res.ok(results);
}
});
});
Unfortunately, it doesn't. The returned results is always an empty array.