I have a Record model with many dynamic attributes. I want to make a request to the model an send the response as JSON to the client. But i want to exclude fields like _id and all foreign_keys in this model.
I found an interessting answer how to exclude the values of some keys: How do I exclude fields from an embedded document in Mongoid?, but the keys in the response still exists.
I got:
{
"_id": 1,
"name": "tom"
}
And the without method makes:
{
"_id": nil,
"name": "tom"
}
But i want:
{
"name": "tom"
}
Is it possible to remove or exclude some keys and the values from the result?
You don't want to remove fields from the mongoid document, what you want to do is remove fields from the generated json.
In your controller, do
render :json => #model.to_json(:except => :_id)
Documentation for the to_json method http://apidock.com/rails/ActiveRecord/Serialization/to_json
taken from the mongodb documentation at: http://docs.mongodb.org/manual/reference/method/db.collection.find/
Exclude Certain Fields from the Result Set
The following example selects documents that match a selection criteria and excludes a set of fields from the resulting documents:
db.products.find( { qty: { $gt: 25 } }, { _id: 0, qty: 0 } )
The query returns all the documents from the collection products where qty is greater than 25. The documents in the result set will contain all fields except the _id and qty fields, as in the following:
{ "item" : "pencil", "type" : "no.2" }
{ "item" : "bottle", "type" : "blue" }
{ "item" : "paper" }
i suppose mongoid is setting the _id attribute to nil since mongoid models have a defined set of attributes (even if they are dynamic, _id, _type etc are defined). maybe you can try it with the mongodb driver.
but i think RedXVII answer is the more practical way to go
Related
I have query like this:
query {
organizations {
id
name
itemA {
fieldA
fieldB
}
}
}
returns
"data": {
"organizations": [
{
"id": 123,
"name": "first org",
"itemA": {
"fieldA": "some value A",
"fieldB": "other value B",
}
},
{
"id": 321,
"name": "other org",
"itemA": {
"fieldA": "other value A",
"fieldB": "value B",
}
}
]
}
One user have access to multiple organizations, but with different access rights for each org.
I need to have organization.id when fieldA and fieldB are resolved to validate access.
I tried to use context.merge_scoped!(organiozation_id: org.id) in resolver for a field, that returns single org.
Looks like it do what I need, child fields received correct value in context but I'm not sure. There is no documentation for that method and for scoped_context in general.
Also, if scoped_context is what I need, how can I set it for a list of items?
UPD: sample query
query {
organizations { // I need to pass item of this list to resolver of ItemA
someModel{
otherModel {
itemA // access depened on organization`
}
}
}
}
Feature was documented in newer version:
https://graphql-ruby.org/queries/executing_queries.html#scoped-context
I'm not 100% sure I got your problem, but I think what you need should be "transparent" to GQL.
You need two things to correctly list "items" for an organization: 1. which organization and 2. who is asking:
# type organization
def itemA
object # this is 1, the organization, current node in the graph
.get_fields_accessible_by(context[:who_is_asking]) # this is requirement 2
end
As you can see, there seems not to be a reason to manipulate context at all. (Unless I missed the point completely, so feel free to amend your question to clarify).
Could you try :
context[:organisation] = object #set this value in your organisation model
access it in another model using, current[:organisation]
Additionally, you can create helper method
something like
def current_organisation
context[:current_organisation]
end
Thanks
I am working with Apollo GraphQL and have to call nested query .But while call the Query in .graphql file it showing
Syntax error : Expected Name, found {
Let me know how to call Nested query of GraphQL.
I have to call getAllproduct{....} query with the specified parameters.Here the FilterInput having the parameter as location with another pattern of query , so I don't know how to call this nested query.Anyone please help me to find out the solution.Thanks...
If an argument is an Input Object Type (as opposed to a Scalar), you can include the fields of the Input Object Type by using curly brackets.
query MyProductsQuery {
allProducts(
pageNumber: "someString"
filter: {
title: "someOtherString"
yearFrom: 1900
location: {
city: "yetAnotherString"
state: "FL"
}
}
) {
id
# other product fields
}
}
Of course, hardcoding those values in a .graphql file is not very helpful. You probably want to be able to swap those values out programatically. So here's what that same query looks like with variables:
query MyProductsQuery($pageNumber: String, $filter: FilterInput) {
allProducts(pageNumber: $pageNumber, filter: $filter) {
id
# other product fields
}
}
Your variables are passed in separately from your query and unlike your query, are not a GraphQL document. They are just JSON:
{
"pageNumber": "someString",
"filter": {
"title": "someOtherString",
"yearFrom": 1900,
"location": {
"city": "yetAnotherString",
"state": "FL"
}
}
}
So I have a json (in text field) and I'm using postgresql and I need to query the field but it's nested a bit deep. Here's the format:
[
{
"name":"First Things",
"items":[
{
"name":"Foo Bar Item 1",
"price":"10.00"
},
{
"name":"Foo Item 2",
"price":"20.00"
}
]
},
{
"name":"Second Things",
"items": [
{
"name":"Bar Item 3",
"price":"15.00"
}
]
}
]
And I need to query the name INSIDE the items node. I have tried some queries but to no avail, like:
.where('this_json::JSON #> [{"items": [{"name": ?}]}]', "%#{name}%"). How should I go about here?
I can query normal JSON format like this_json::JSON -> 'key' = ? but need help with this bit.
Here you need to use json_array_elements() twice, as your top level document contains array of json, than items key has array of sub documents. Sample psql query may be the following:
SELECT
item->>'name' AS item_name,
item->>'price' AS item_price
FROM t,
json_array_elements(t.v) js_val,
json_array_elements(js_val->'items') item;
where t - is the name of your table, v - name of your JSON column.
I have a Collection Report embeds submissions
class Report
embeds_many :submissions
class Submission
embedded_in :report
field :date_submitted, type: TimeWithZone
field :mistakes, type: Integer
I am trying to create a scope on Report
I want to add a scope query with two parts
get the latest submission (given by max date_submitted) that also has zero mistakes
I can create a scope for the mistakes part, but cannot work out how to get the latest submission
scope :my_scope, where("submissions.mistakes" => 0)
So this report would be returned as it's last enter in submissions has zero mistakes
Report
"submissions" : [
{
"date_submitted" : ISODate("2014-01-28T13:00:00Z"),
"mistakes" : 11
},
{
"date_submitted" : ISODate("2014-03-08T13:00:00Z"),
"mistakes" : 0
}
]
where this one wouldn't be returned
Report
"submissions" : [
{
"date_submitted" : ISODate("2014-01-28T13:00:00Z"),
"mistakes" : 0
},
{
"date_submitted" : ISODate("2014-03-08T13:00:00Z"),
"mistakes" : 11
}
]
This is because you are not filtering the element of the embedded array but the document that contains that element.
There could be an $elemMatch clause here which allows you to combine the conditions on a single element. But find does not have any operation for getting the max value as it were. This is not to be confused with the $max query modifier, which actually clips the index in use to not search beyond those bounds.
So here you use aggregate:
db.collection.aggregate([
// Optionally query to match and filter your documents.
//{ "$match: { /* Same conditions as find */ } },
// Unwind the array
{ "$unwind": "$submissions" },
// Filter all but 0 mistakes
{ "$match": { "submissions.mistakes": 0 } },
// Group the results, taking the max entry and presuming by document `_id`
{ "$group": {
"_id": "$_id",
"date_submitted": { "$max": "$submissions.date_submitted" }
}}
])
That is the general process for filtering the elements of an array. You may look into your driver implementation of aggregate, but the form is always the pipeline represented as an array of documents (hashes) in this form. Possibly using the moped form for getting the collection method. So something like:
Report.collection.aggregate([ /* stages */ ])
For more information on returning the original document form if that is what your requirement is then see here.
I have a problem "joining" some documents in a view. Here's my schema: Documents with type "category" can hold an embedded array of ids to documents with type "page". Both have a field "name".
My Documents:
{
"_id": "887c28dcf6dd8429d404d276b900b203",
"_rev": "3-c4d1e0c8378bb0081b5fe3522ee649a0",
"TYPE": "category",
"NAME": "Home",
"PAGES": [
{"PAGE_ID": "887c28dcf6dd8429d404d276b900ad8f"},
{"PAGE_ID": "887c28dcf6dd8429d404d276b900b203"},
{"PAGE_ID": "887c28dcf6dd8429d404d276b900bae0"}
]
}
{
"_id": "887c28dcf6dd8429d404d276b9008c01",
"_rev": "1-afd54c654ae5afa56a3fbd7b1ba119d2",
"TYPE": "page",
"NAME": "Foo"
}
Now I want to join these in a view with this map function:
function(doc) {
if (doc.TYPE == "category") {
for (id in doc.PAGES) {
emit(doc.NAME, doc.PAGES[id].PAGE_ID);
}
}
}
But instead of the PAGE_ID I want the NAME of the referencing document.
This is basically the example from the CouchDB wiki, but they don't show the map function. So any ideas?
You need to include a _id field somewhere in your output value. After that, you use include_docs=true and the view will include the linked document instead of the source document. For example:
function(doc) {
if (doc.TYPE == "category") {
for (var x = 0; x < doc.PAGES.length; x++) {
emit(doc.NAME, { _id: doc.PAGES[x].PAGE_ID });
}
}
}
When you query this view, you add include_docs=true to your URL. And your view output will add a new field to each row called doc. Ordinarily, that field will contain the full source document. In this case, it will include the linked document you are referring to.
EDIT Btw, you're using the for...in loop incorrectly. A for...in is used to loop over the properties of an object. You need to use a simple for loop to iterate an array like this.