I have two GraphQL type:
type Author {
id: String!
name: String!
}
type Book {
id: String!
author: Author!
name: String!
}
In my database, it is implemented by a foreign key inside the books table:
table authors (pseudo code)
`id` INTEGER UNSIGNED
`name` STRING
table books (pseudo code)
`id` INTEGER UNSIGNED
`author_id` INTEGER UNSIGNED REFERENCE `authors.id`
`name` STRING
So when I resolve a GraphQL query like:
query allTheBooks {
id
name
author {
id
name
}
}
I would like to do only one SELECT SQL query like:
SELECT books.id, books.name, authors.id, authors.name
FROM books
LEFT JOIN authors ON authors.id = books.author_id
Instead of the current:
SELECT books.id, books.name, books.author_id
FROM books
SELECT authors.id, authors.name
FROM authors
WHERE author.id = [one the the books.author_id of the first SELECT]
SELECT authors.id, authors.name
FROM authors
WHERE author.id = [one the the books.author_id of the first SELECT]
[...]
Is there a way to know which "child fields" are queried in a GraphQL resolver ?
Thank you in advance for your answer !
I just discovered that in the fourth parameter gived at the resolver, there where an array of the queried fields: info.fieldNodes[0].selectionSet.selections.
I didn't found any documentation about this, and I wonder what represent the fieldNodes array... (and dont like to access the first element that way without knowing it...).
The selections object contains an array like this:
[
{
kind: 'Field',
alias: undefined,
name: { kind: 'Name', value: 'id', loc: [Object] },
arguments: [],
directives: [],
selectionSet: undefined,
loc: { start: 36, end: 38 }
},
{
[...]
},
...
]
Here, the value: 'id' match the name of the queried field of the related author.
If I go a level deeped, the selectionSet: undefined becomes an object and the pattern repeat itself recursively...
Related
I have a collection of persons with a group property. Group value is a random string, which I don't know when I make my query. Some persons group values will possibly be the same.
I want to write a query to retrieve only one person per group (which person is returned in the group is non relevant for the moment).
I suppose I have to write some kind of aggregation. But I only read about examples aggregating on known values... Instead I need to aggregate on unknown values...
My schema is something like:
const schemaPersons = new Schema({
name: {
type: String,
required: true,
},
group: {
type: String,
},
};
You can write aggregation query using $group stage:
$group stage, group by group field, and get only first person's root document in person field
Persons.aggregate([
{
$group: {
_id: "$group",
person: { $first: "$$ROOT" }
}
}
]);
Playground
In Mongoose, I have two collections, with one referencing the other. Is it possible to have a find query that selects records based on a value in the other. An example of what I am try to get at (not actual schemas):
const CarModelSchema = new mongoose.Schema({
name: String,
brand: { type: mongoose.Schema.Types.ObjectId, ref: 'CarBrand' }
});
const CarBrandSchema = new mongoose.Schema({
name: String,
country: String
});
I then want to perform a query of the form, without needing to do two queries:
CarModelSchema.find({ 'brand.country': 'GER' });
So far I haven't been able to make this work, so I am wondering whether this can be done in Mongo or whether I am approaching it wrong?
Yes it is possible.
I realize you don't have models for your schemas so add them like this:
const CarModel = mongoose.model('CarModel', CarModelSchema);
const CarBrand = mongoose.model('CarBrand', CarBrandSchema);
Also brands should be defined like this:
brand: [{ type: mongoose.Schema.Types.ObjectId, ref: 'CarBrand' }] //added the brackets
You can then run a find query to filter by country by doing the following:
CarModel.
find(...).
populate({
path: 'brand',
match: { country: { $eq: 'GER' }},
// You can even select the field you want using select like below,
select: 'name -_id',
//Even limit the amount of documents returned in the array
options: { limit: 5 }
}).
exec();
And that should do it, as long as the ObjectIds saved in brands array in the CarModel collection are valid or exist.
Using match in your population will do the work.
CarModel.find()
.populate({
path: 'brand',
model: CarBrandModel,
match: { country: { $eq: 'GER' }},
})
.exec()
Keep in mind you have to define CarModel and CarBrandModel like this:
const CarModel = mongoose.model('CarModel', CarModelSchema)
const CarBrandModel = mongoose.model('CarBrandModel', CarBrandSchema)
Yes, you are doing it wrong.
In CarModelSchema.brand there is not string saved, there is ObjectId saved, therefore you have to find that ObjectId (the reference).
You can do it manually - first finding the CarBrandSchema.find({ 'country': 'GER' }); and then use its ObjectId (=_id), or you can use https://mongoosejs.com/docs/populate.html to populate your CarModel with the CarBrand object.
I would like to query objects in array of objects with specific field in google cloud firestore,
I have collection structured like this :
...
{
name: "shoes 1",
amount:150,
productors: [
{
id : "a001",
name : "productor 1"
},
{
id: "a002",
name: "productor 2"
}
...
]
...
}
{
name: "shoes 2",
amount:80,
productors: [
{
id : "a002",
name : "productor 2"
},
{
id: "a001",
name: "productor 1"
}
...
]
...
}
...
and I would like to query this collection to get all docs that have in productors array, produtor with the id = e001.
I work in a nodejs environment, using firestore-admin-sdk
This is not possible with Cloud Firestore. You can't query for properties of objects within an array. You can only query an array for the entire value of one of its items (the full object).
For this query, you will need a separate field to query, perhaps array that contains only the id values you want to find. You can use an array-contains type query for that.
Below is an image of what my user MongoDB document looks like. I have a skills array which contains objects with the follwing structure.
{
name: String,
points: Number,
skill: Schema.Types.ObjectId
}
Here's a screenshot of an actual user document, you can see the skill with the name html
Now I want to create a search query that would match the name property of one these objects in the skills array. e.g if my input is htm it would match with a user that has a skill with the name html. I tried it the way below, but it doesn't seem to be working. Can someone suggest me how to successfully do this?
const createSkillsQuery = (user, input) => User.find({
$and: [
{ skills: { name: { $regex: input, $options: 'i' } } },
{ _workspace: user._workspace }
]
}).select('profile_pic full_name email created_date');
You need to use the dot notation here.
"skills.name": { $regex: input, $options: 'i' }
Hi I want to get the type names of the query in graphql. It should not have scalar and enumerated types.
schema {
query: Query
}
type LearningResource{
id: ID
name: String
type: String
children: [LearningResource]
}
type Query {
fetchLearningResource: LearningResource
}
When I run fetchLearningResource query then I want to get the type of it like here LearningResource. Any way to do this in GraphQL ?
You should find the Type of the Query as a string in the Response, search for __typename.
E.g.
response =>
{
fetchLearningResource: {
id: <id>
name: "name"
type: "type"
children: [...]
__typename: "LearningResource"
}
}
EDIT:
If you want to fetch the query definition before you query. You could get the introspection query from the server. Here are some links:
introspection query error
retrieve whole schema question