I want to perform a query that will return all the documents that contain a given string in ANY of their fields. For example, say I have a "users" table and I'm looking for all the documents that contain "john", the returned result can be:
[{"first_name": "jhon", "last_name": "watson"}, {"first_name": "elton", "last_name": "john"}, {"first_name": "sherlock", "last_name": "holmes", "best_friend": "john watson"}]
How do I do that in rethinkdb? javascript answer will do, python implementation will be better.
Unfortunately this query is made harder by the fact that ReQL doesn't have a values function like python. However it does have a keys function so let's just use that to make a values function like so:
def values(doc):
return doc.keys().map(lambda x: doc[x])
Now that we have that finding a document that contains a string in one of its keys is pretty easy:
def has_str(doc, str):
return values(doc).map(match(str)).reduce(lambda x,y: x | y)
Finally we can put it all together:
r.table("users").filter(lambda doc: has_str(doc, str))
You could in theory do this all in one big query but I really like breaking up even moderately complicated queries. The really nice thing about this approach is that if it doesn't work each function has a pretty simple set of semantics so you can debug them individually.
It looks like you can just coerce the entire document into a string, and then search on that:
r.db('database').table('table).filter(function(doc) {
return doc.coerceTo('string').match('querystring');
});
This solution doesn't feel as slick as the other provided, but runs much faster for me and provides the same results so far.
For anyone who has found themselves here trying to figure this out in javascript, this roughly translates to:
function values(doc) {
return doc.keys().map(function(key) {
return doc(key);
});
}
function contains(doc, string) {
return values(doc).map(function(val) {
return r.branch(val.match(string), true, false);
}).reduce(function(left, right) {
return left.or(right);
});
}
var query = r.db('database').table('table').filter(function(doc) {
return contains(doc, "some string");
});
query.run().then(function(results) {
console.log(results);
});
Improvements welcome!
Related
I'm fairly new to the concept of GraphQL and I'm wondering whether it is considered bad practice to return all results in a query when the argument is left out.
If, for example, I run this query:
query {
item(title: "test") {
title,
properties {
key,
value
}
}
}
It will return all properties, but if I run this query:
query {
item(title: "test") {
title,
properties(group: "test-group") {
key,
value
}
}
}
It will return all properties in the "test-group".
I tried searching for this question online and on StackOverflow but I couldn't find the answer I need.
I did manage to find the following example on the GraphQL website though, but I'm not sure whether it's exactly the same:
{
human(id: "1000") {
name
height
}
}
{
human(id: "1000") {
name
height(unit: FOOT)
}
}
If anyone could shed some light on this, I'd be very thankful!
It depends on if an item can possibly has many properties that has a chance to cause the server to run out of memory if multiple users retrieves an item 's all properties at the same time. If the chance is very very very small , it is very normal to just returning all properties if user left out the properties field 's argument.
Otherwise , it is not so good to always returning all properties due to the chance to bring down the server because of running out of memory. In this case, you can apply some sensible default to return only the first N-th properties to prevent it from happening.
It is equivalent to the REST API that returning a list of records. If an user does not specify the query parameter for pagination , it will by default return a sensible number of records but not returning all records.
This works fine
query QryTopics {
topics {
nodes {
name
topicId
count
}
}
}
But I want a filtered result. I'm new to graphql but I see a param on this collection called 'where', after 'first', 'last', 'after' etc... How can I use that? Its type is 'RootTopicsTermArgs' which is likely something autogenerated from my schema. It has fields, one of which is 'childless' of Boolean. What I'm trying to do, is return only topics (a custom taxonomy in Wordpress) which have posts tagged with them. Basically it prevents me from doing this on the client.
data.data.topics.nodes.filter(n => n.count !== null)
Can anyone direct me to a good example of using where args with a collection? I have tried every permutation of syntax I could think of. Inlcuding
topics(where:childless:true)
topics(where: childless: 'true')
topics(where: new RootTopicsTermArgs())
etc...
Obviously those are all wrong.
If a custom taxonomy, such as Topics, is registered to "show_in_graphql" and is part of your Schema you can query using arguments like so:
query Topics {
topics(where: {childless: true}) {
edges {
node {
id
name
}
}
}
}
Additionally, you could use a static query combined with variables, like so:
query Topics($where:RootTopicsTermArgs!) {
topics(where:$where) {
edges {
node {
id
name
}
}
}
}
$variables = {
"where": {
"childless": true
}
};
One thing I would recommend is using a GraphiQL IDE, such as https://github.com/skevy/graphiql-app, which will help with validating your queries by providing hints as you type, and visual indicators of invalid queries.
You can see an example of using arguments to query terms here: https://playground.wpgraphql.com/#/connections-and-arguments
I have this mongo query (java):
TextQuery.queryText(textCriteria).sortByScore().limit(configuration.getSearchResultSize())
which performs a text search and sort by score.
I gave different wiehgt to different fields in the docuemnt, and now I'd like to retrieve only those results with score lower then 10.
is there a way to add that criteria to the query?
this didn't work:
query.addCriteria(Criteria.where("score").lt(10));
if the only way is to use aggregation - I need a mongoTemplate example for that.
in other words
how the do I translate the following mongo shell aggregate command, to java spring's mongoTemplate command??
can't find anywhere how to use the aggregate's match() API with the $text search component (the $text is indexed on several different fields):
db.text.aggregate(
[
{ $match: { $text: { $search: "read" } } },
{ $project: { title: 1, score: { $meta: "textScore" } } },
{ $match: { score: { $lt: 10.0 } } }
]
)
Thanks!
Please check with below code sample, MongoDB search with pagination code in java
BasicDBObject query = new BasicDBObject()
query.put(column_name, new BasicDBObject("$regex", searchString).append("$options", "i"));
DBCursor cursor = dbCollection.find(query);
cursor.skip((pageNum-1)*limit);
cursor.limit(limit);
Write a loop and and call the above code from loop and pass the values like pageNum starts from 1 to n and limit depends on your requirement. check the cursor is empty or not. If empty skip the loop if not continue calling the above code base.
Hope this will be helpful.
I have below a structured Mongo Document:
{
"_id": value,
"imageShared": {
"imageid": value,
"commentdatadoc": [
{
"whocommented": value,
"commenttext": value,
"commenttimestamp": isodate(111)
},
{
"whocommented": value,
"commenttext": value,
"commenttimestamp": isodate(444)
},
{
"whocommented": value,
"commenttext": value,
"commenttimestamp": isodate(222)
}
]
}
};
Here I want to sort the field commenttimestamp desc. I tried the way below but it is not working...
Query getComments = new Query();
getComments.addCriteria(Criteria.where("imageShared.imageId").is(imageId)).
with(new Sort(Sort.Direction.DESC,"imageShared.commentDataDoc"));
SharedMediaCollec sharedMediaCollec = mongoTemplate.findOne(getComments, SharedMediaCollec.class);
Does anyone have an idea how to sort a document field which is inside array?
When you need to get all documents anyway, it might be far easier to do the sorting in C# after you received the data from MongoDB. An elegant way to do this automatically would be to represent the commentdatadoc array in your C# object with a SortedSet.
But when you definitely want a database-sided solution, you can do it with an aggregation pipeline consisting of a $match-step, a $unwind step and a $sort step. To perform an aggregation with the C# driver, call collection.Aggregate and then set the aggregation stages at the returned IAggregateFluent interface.
I have two documents that looks a bit like so:
Doc
{
_id: AAA,
creator_id: ...,
data: ...
}
DataKey
{
_id: ...,
credits_left: 500,
times_used: 0,
data_id: AAA
}
What I want to do is create a view which would allow me to pass the DataKey id (key=DataKey _id) and get both the information of the DataKey and the Doc.
My attempt:
I first tried embedding the DataKey inside the Doc and used a map function like so:
function (doc)
{
if (doc.type == "Doc")
{
var ids = [];
for (var i in doc.keys)
ids.push(doc.keys[i]._id);
emit(ids, doc);
}
}
But i ran into two problems:
There can be multiple DataKey's per
Doc so using startkey=[idhere...]
and endkey=[idhere..., {}] didn't
work (only worked if the key happend
to be the first one in the array).
All the data keys need to be unique, and I would prefer not making a seperate document like {_id = datakey} to reserve the key.
Does anyone have ideas how I can accomplish this? Let me know if anything is unclear.
-----EDIT-----
I forgot to mention that in my application I do not know what the Doc ID is, so I need to be able to search on the DataKey's ID.
I think what you want is
function (doc)
{
if (doc.type == "Doc")
{
emit([doc._id, 0], doc);
}
if(doc.type == "DataKey")
{
emit([doc.data_id, 1], doc);
}
}
Now, query the view with key=["AAA"] and you will see a list of all docs. The first one will be the real "Doc" document. All the rest will be "DataKey" documents which reference the first doc.
This is a common technique, called CouchDB view collation.