RTK Query url with parameter which is an array - redux-toolkit

I am currently trying to pass in an array to a query which will be used as parameters but keeping encountering an issue that the object doesn't seem to take an array in the parameters and doesn't format the url param string as I need.
Here is my array that is passed into my RTK hook:
filterArguments = [1,2]
RTK Query:
getFood: builder.query({
// The URL for the request is '/fakeApi/posts'
query: (filterArguments) => ({
url:'/user/food/',
params: {
...filterArguments
}
}),
providesTags:['Food']
}),
This is bringing back an error or if i fiddle around with it an send an object through it brings back the following URL ignoring other items in the object of the same name:
test:8000/api/?filter=1
However this is not the desired result, the desire url result from passing an array of filter id's would be:
test:8000/api/?filter[]=1&filter[]=2
is this achievable in RTK query? and how would i achieve this?

redux-toolkit doesnt implement any special http library. It uses fetch under the hood. For params, it uses URLSearchParams(). So the API will be similar. Since URLSearchParams() doesnt support your params notation, you can use the query-string library:
const queryString = require('query-string');
getFood: builder.query({
query: (filterArguments) => ({
url:'/user/food/' + queryString.stringify({filter: filterArguments}, {arrayFormat: 'bracket'}),
}),
providesTags:['Food']
}),

Related

Suppress value types in MongoDB Stitch function

A Stitch function returns value types for each non-string field. I believe this is because functions return data in MongoDB Extended JSON.
The Mongo Shell, on the other hand, returns standard JSON, and no value types.
How do I suppress value types returned by a MongoDB function? Is it possible to convert EJSON back to JSON?
For a date field, for example, the Mongo Shell returns:
"dob" : ISODate("1995-01-11T00:00:00.000-07:00")
The same query in a Stitch function returns:
"dob": {
"$date": {
"$numberLong": "232182000000"
}
My Stitch function looks like this:
exports = function(){
const collection = context.services.get("mongodb-atlas").db("mydb").collection("mycollection");
const doc = collection.find().toArray();
return doc;
};
Is there a helper function that can strip out the value types? Something like...
exports = function(){
const collection = context.services.get("mongodb-atlas").db("mydb").collection("mycollection");
const doc = collection.find().toArray();
const noValueTypes = doc.stripValueTypes()
return noValueTypes;
};
When a Function result is passed to the client, it is indeed serialized as EJSON.
Ideally, your client can parse EJSON back into regular JS objects, e.g. with the EJSON library, which is also built into the Stitch SDK.
Of course, if you are using the Stitch SDK, calling the function directly is even better.
Another option is to use the response object to pass JSON, like so:
exports = function(request, response) {
// ... get data ...
response.addHeader(
"Content-Type",
"application/json"
);
response.setBody(JSON.stringify(myData));
};
Note that JSON can't represent some special BSON types, such as object id, so you will want to keep this in mind when deciding what data to return.

Mongoose - populate return _id only instead of a Object [duplicate]

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as
Person.find({})
.populate('books movie', 'title pages director')
.exec()
However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:
Person.find({})
.populate('books', 'title pages')
.populate('movie', 'director')
.exec()
which gives me the expected result and queries.
But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.
After looking into the sourcecode of mongoose, I solved this with:
var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];
Person.find({})
.populate(populateQuery)
.execPopulate()
you can also do something like below:
{path:'user',select:['key1','key2']}
You achieve that by simply passing object or array of objects to populate() method.
const query = [
{
path:'books',
select:'title pages'
},
{
path:'movie',
select:'director'
}
];
const result = await Person.find().populate(query).lean();
Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!
This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html
Let's say you have a BookCollection schema which contains users and books
In order to perform a query and get all the BookCollections with its related users and books you would do this
models.BookCollection
.find({})
.populate('user')
.populate('books')
.lean()
.exec(function (err, bookcollection) {
if (err) return console.error(err);
try {
mongoose.connection.close();
res.render('viewbookcollection', { content: bookcollection});
} catch (e) {
console.log("errror getting bookcollection"+e);
}
//Your Schema must include path
let createdData =Person.create(dataYouWant)
await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

vue js 2 - for loop in multiple rest calls fetchData

I am trying to get wp-rest and Vuejs 2 to work together, so far things are coming along nicely apart from this one rest call that requires another request for the design to be complete. Essentially I want to be able to iterate / loop through the first request and dynamically change update the second request.
And my second question is performance, overall the rest calls are taking a bit longer to load - is there something I can do to optimize?
Context:
The first result data gives me an id, slug and title to all the posts I want to display only on the homepage as featured - through that id or slug I want to pass it to the second request - so I can pull in more information about those posts - like featured image and other meta field data.
<pre>export default {
name: 'work',
data () {
return {
loading: false,
page: null,
pagesingle: null,
error: null
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
this.$http.get('/cms/wp-json/wp/v2/pages/?slug=work&_embed')
.then(result => {
this.page = result.data
this.$http.get('/cms/wp-json/wp/v2/cases-studes/?slug=case-study-name').then(
result => this.pagesingle = result.data
);
})
}
}
}</pre>
I think you want to look at Promise.all. It will take an array of promises, wait for them all to complete, and then resolve with an array of results.
You would build your array of promises based on the array of slugs and ids in your first request. Maybe something like
const promises = result.data.articles.map((article) =>
this.$http.get(`/cms/wp-json/wp/v2/cases-studies/?slug=${encodeURIComponent(article.slug)}`)
);
Getting the results is as easy as
Promise.all(promises).then((results) => {
this.arrayOfSinglePages = results.map((result) => result.data);
});
Now your this.page has the array of id (and stuff) and this.arrayOfSinglePages has the page details for each of them in the same order.

Query sailsjs blueprint endpoints by id array using request

I'm using the request library to make calls from one sails app to another one which exposes the default blueprint endpoints. It works fine when I query by non-id fields, but I need to run some queries by passing id arrays. The problem is that the moment you provide an id, only the first id is considered, effectively not allowing this kind of query.
Is there a way to get around this? I could switch over to another attribute if all else fails but I need to know if there is a proper way around this.
Here's how I'm querying:
var idArr = [];//array of ids
var queryParams = { id: idArr };
var options: {
//headers, method and url here
json: queryParams
};
request(options, function(err, response, body){
if (err) return next(err);
return next(null, body);
});
Thanks in advance.
Sails blueprint APIs allow you to use the same waterline query langauge that you would otherwise use in code.
You can directly pass the array of id's in the get call to receive the objects as follows
GET /city?where={"id":[1, 2]}
Refer here for more.
Have fun!
Alright, I switched to a hacky solution to get moving.
For all models that needed querying by id arrays, I added a secondary attribute to the model. Let's call it code. Then, in afterCreate(), I updated code and set it equal to the id. This incurs an additional database call, but it's fine since it's called just once - when the object is created.
Here's the code.
module.exports = {
attributes: {
code: {
type: 'string'//the secondary attribute
},
// other attributes
},
afterCreate: function (newObj, next) {
Model.update({ id: newObj.id }, { code: newObj.id }, next);
}
}
Note that newObj isn't a Model object as even I was led to believe. So we cannot simply update its code and call newObj.save().
After this, in the queries having id arrays, substituting id with code makes them work as expected!

How to expose a Mongoose / MongoDB query as an Express route

I would like to create an express route for creating a RESTful url passing its query parameters to the Mongoose query. Something like this (not working) code mapping the limit and sort parameters from the url and otherwise using defaults. The url would be:
myhost/processes?limit=20&sort=-modified
exports.find = function(req, res) {
var options = {
limit : 100,
sort: '-created'
};
_(options).extend(req.query);
Process.find(options, function(err, process) {
res.send(process);
});
}
I only know how to pass the query parameters to individual methods like find() and sort() that no way to map this in a more automatic fashion. Or is what I'm trying to do a bad idea in terms of RESTful api? I'm using Mongoose but but I would be interested in a solution using the native driver if that helps.
Assuming you're using the underscore library's extend you can do it like this:
exports.find = function(req, res) {
var options = {
limit : 100,
sort: {created: -1}
};
_.extend(options, req.query);
Process.find({}, null, options, function(err, process) {
res.send(process);
});
}
The options parameter will be passed into the Query#setOptions method, and many of the options are passed through directly to the node.js native driver, so for things like sort see the native find docs. As you can see, the format of sort isn't conducive to being provided in a URL parameter.
It's more secure to only expose support for specific options and then individually pull those in from req.query rather than using extend, but either way can work.