Mongoid failing to find document by nested ID - ruby

I have a collection with documents that look something like this:
{
_id: ObjectId("521d11014903728f8d000006"),
association_chain: [
{
name: "Foobar",
id: ObjectId("521d11014903728f8d000005")
}
],
// etc...
}
I can search by the name attribute with this query:
#results = Model.where 'association_chain.name' => 'Foobar'
This returns the results as expected. However, when I try to search using the id attribute:
#results = Model.where 'association_chain.id' => '521d11014903728f8d000005'
There are no results. As far as I can tell, the query that Mongoid generates looks correct:
MOPED: 127.0.0.1:27017 QUERY database=x collection=x selector={"$query"=>{"association_chain.id"=>"521d11014903728f8d000005"}, "$orderby"=>{"created_at"=>-1}} flags=[] limit=25 skip=0 batch_size=nil fields=nil (244.7259ms)
What am I doing wrong?

You are searching for the string. Try searching for an ObjectId, like
#results = Model.where 'association_chain.id' => BSON::ObjectId('521d11014903728f8d000005')

Related

Sort GraphQL query results in the exact order of input array

I need to get a number of items from a GraphQL enabled database (no control over its schema) and output them in the exact order called.
For example, if the database holds the items 1,2,3 in that respective order I need to get them as 3,1,2.
Query:
{items(filter: {id: {_in: ["3","1","2"] } } ) {data}}
Actual result:
{"data": {"items": [{"data": "data-from-1"},{"data": "data-from-2"},{"data": "data-from-3"}]}}
Expected result:
{"data": {"items": [{"data": "data-from-3"},{"data": "data-from-1"},{"data": "data-from-1"}]}}
So I guess that what I'm looking for is a 'meta' operator that relates to other operators rather than the actual query – something like:
sort:["_in"] or orderby:{operator:"_in"}
...but I didn't manage to find out if such a thing exists or not.
So is it possible in general or maybe in some flavour of GraphQL? Or is it my only choice to prebuild a query with aliases and do it like this:
{
_3: items(filter:{id: { _eq: "3" }}){data}
_1: items(filter:{id: { _eq: "1" }}){data}
_2: items(filter:{id: { _eq: "2" }}){data}
}
Which GraphQL client are you using?
If you're using Apollo, and you really don't have access to the schema/resolvers in the server, you can create a local field and resolve it on your own, and so you can manipulate as much as you want.
Reference
https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#defining
Basically, if you're querying a field like:
query {
someQuery(someFilter: {foo: "bar"}) {
items {
data
}
}
}
You can create a local field and write a typePolicy to it. Then you can query something like:
query {
someQuery(someFilter: {foo: "bar"}) {
items {
data
}
parsedItems #client
}
}
Then you can get data from ìtems and resolve parsedItems locally as you want.

How do I add an OR condition in a graphql where statement?

I cannot get a WHERE statement working with an 'OR' condition in Strapi via graphql playground.
I would like to return all results where either the 'title' OR 'content' fields contain the search_text.
I have tried the following:
articles(where: {
or: [
{"title_contains" : "search_text"},
{"content_contains" : "search_text"}
]
}) {
title
content
}
but an error is returned.
ERROR: "Your filters contain a field 'or' that doesnt appear on your model definition nor it's relations.
Some statements that work (but not what I am after):
where: { "title_contains" : "sometext" }
working, but behaves as an 'AND'
where: {
"title_contains" : "search_text",
"content_contains" : "search_text"
}
As of July it's possible to do it like this
(where: { _or: [{ someField: "1" }, { someField2: "2" }] })
The workaround here is to create a custom Query and make a custom database query that matches your need.
Here is how to create a custom GraphQL query:
https://strapi.io/documentation/3.0.0-beta.x/guides/graphql.html#example-2
To access the data model, you will have to use strapi.models.article (For an Article model) and inside this variable, you will access to native Mongoose or Bookshelf function. So you will be able to query with an OR

how to use ruby's mongo driver to update a mult-level document

How do I use the ruby's mongo driver to update a multi-level document. For example, here's part of the docuement:
...
"group_overrides": [
{
"additional_filesystem_gb": 0,
"components": [
{
"comp": "jbosseap-6",
"cart": "jbosseap-6",
"cart_id": ObjectId("5423d363f4b25eea0b000021")
}
],
"max_gears": 1
}
],
In the mongo-shell I can do something like:
db.applications.update({name:"ulmuqhfv"}, {$set: {"group_overrides.0.additional_filesystem_gb": 1}})
and the document will be updated. When I tried the following:
db.update('applications', {"app_name"=>"ulmuqhfv"}, {"$set"=>{"group_overrides.0.additional_filesystem_gb"=>1})
It failed. What's the correct syntax for updating an array?
db is an instance of a wrapper class around the ruby mongo driver. Here's what the update method looks like:
def update(c_name, selector, opts)
db = #db.collection(c_name)
if opts
db.update(selector, opts).to_a
else
db.update(selector).to_a
end
end
as simple as that:
db['applications'].update({"app_name"=>"ulmuqhfv"}, {"$set"=>{"group_overrides.0.additional_filesystem_gb"=>1})
you need to access your collection as you access hash keys, db['applications'] will return the collection object
mongo_connection = Mongo::Connection.new("localhost", 27017) # your connection settings
db = mongo_connection.db("mydb") # select database
coll = db['applications'] # select collection
coll.update({"app_name"=>"ulmuqhfv"}, {"$set"=>{"group_overrides.0.additional_filesystem_gb"=>1})
you can learn more here under Getting a Collection section

tire terms filter not working

I'm trying to achieve a "scope-like" function with tire/elasticsearch. Why is this not working, even when i have entries with status "Test1" or "Test2"? The results are always empty.
collection = #model.search(:page => page, :per_page => per_page) do |s|
s.query {all}
s.filter :terms, :status => ["Test1", "Test2"]
s.sort {by :"#{column}", "#{direction}"}
end
The method works fine without the filter. Is something wrong with the filter method?! I've checked the tire doku....it should work.
Thanks! :)
Your issue is most probably being caused by using the default mappings for the status field, which would tokenize it -- downcase, split into words, etc.
Compare these two:
http://localhost:9200/myindex/_analyze?text=Text1&analyzer=standard
http://localhost:9200/myindex/_analyze?text=Text1&analyzer=keyword
The solution in your case is to use the keyword analyzer (or set the field to not_analyzed) in your mapping. When the field would not be an “enum” type of data, you could use the multi-field feature.
A working Ruby version would look like this:
require 'tire'
Tire.index('myindex') do
delete
create mappings: {
document: {
properties: {
status: { type: 'string', analyzer: 'keyword' }
}
}
}
store status: 'Test1'
store status: 'Test2'
refresh
end
search = Tire.search 'myindex' do
query do
filtered do
query { all }
filter :terms, status: ['Test1']
end
end
end
puts search.results.to_a.inspect
Note: It's rarely possible -- this case being an exception -- to offer reasonable advice when no index mappings, example data, etc. are provided.

Mongoid Complex Query Including Embedded Docs

I have a model with several embedded models. I need to query for a record to see if it exists. the issue is that I will have to include reference to multiple embedded documents my query would have to include the following params:
{
"first_name"=>"Steve",
"last_name"=>"Grove",
"email_addresses"=>[
{"type"=>"other", "value"=>"steve#stevegrove.com", "primary"=>"true"}
],
"phone_numbers"=>[
{"type"=>"work_fax", "value"=>"(720) 555-0631"},
{"type"=>"home", "value"=>"(303) 555-1978"}
],
"addresses"=>[
{"type"=>"work", "street_address"=>"6390 N Main Street", "city"=>"Elbert", "state"=>"CO"}
],
}
How can I query for all the embedded docs even though some fields are missing such as _id and associations?
A few things to think about.
Are you sure the query HAS to contain all these parameters? Is there not a subset of this information that uniquely identifies the record? Say (first_name, last_name, and an email_addresses.value). It would be silly to query all the conditions if you could accomplish the same thing in less work.
In Mongoid the where criteria allows you to use straight javascript, so if you know how to write the javascript criteria you could just pass a string of javascript to where.
Else you're left writing a really awkward where criteria statement, thankfully you can use the dot notation.
Something like:
UserProfile.where(first_name: "Steve",
last_name: "Grove",
:email_addresses.matches => {type: "other",
value: "steve#stevegrove.com",
primary: "true"},
..., ...)
in response to the request for embedded js:
query = %{
function () {
var email_match = false;
for(var i = 0; i < this.email_addresses.length && !email_match; i++){
email_match = this.email_addresses[i].value === "steve#stevegrove.com";
}
return this.first_name === "Steve" &&
this.last_name === "Grove" &&
email_match;
}
}
UserProfile.where(query).first
It's not pretty, but it works
With Mongoid 3 you could use elem_match http://mongoid.org/en/origin/docs/selection.html#symbol
UserProfile.where(:email_addresses.elem_match => {value: 'steve#stevegrove.com', primary: true})
This assumes
class UserProfile
include Mongoid::Document
embeds_many :email_addresses
end
Now if you needed to include every one of these fields, I would recommend using the UserProfile.collection.aggregate(query). In this case you could build a giant hash with all the fields.
query = { '$match' => {
'$or' => [
{:email_addresses.elem_match => {value: 'steve#stevegrove.com', primary: true}}
]
} }
it starts to get a little crazy, but hopefully that will give you some insight into what your options might be. https://coderwall.com/p/dtvvha for another example.

Resources