Rethinkdb - Not Equal (ne) on multiple fields - rethinkdb

I have a document that looks similar to the following
{
...
reactions: [
{
user: 'user_id',
reaction: 'reaction_name'
}, {
user: 'user_id',
reaction: 'reaction_name'
}
]
...
}
I'm trying to remove an item in the array reactions based on a combination of 'user' and 'reaction' which will be unique. How would I go about filtering the reactions array to remove that specific item in rethinkdb using the js driver?
I've tried this
r.db('db_name').table('messages').getAll(
get_single_message
).update({
reactions: r.row('reactions').filter( (item) => {
return item('reaction').ne(body.reaction).and(item('user').ne(body.user))
})
}).run(this._rdbConn)
I understand why it doesn't work (returns all reactions that don't have given reaction, then returns subset of that array that doesn't have certain user).
What I want is for those not equals to be performed in sync so it returns an array that doesn't include items that have the provided reaction AND user. Right now it functions more like reaction OR user.

A buddy helped me out. Here's a solution that works for what I was trying to accomplish, but it does not makes use of not equal. If anyone has another solution that makes use of not equal please share it.
r.db('db_name').table('messages').getAll(
get_single_message
).update({
reactions: r.row('reactions').filter(function (doc) {
return doc('reaction').eq(body.reaction).and(doc('user').eq(body.user)).not()
})
}).run(this._rdbConn)

Here's a possibly more simplified way to do this without .ne:
r.db('db_name').table('messages').getAll(
get_single_message
).update({
reactions: r.row('reactions').difference([{
reaction: body.reaction,
user: body.user
}])
}).run(this._rdbConn)
Just be warned that .difference will remove all instances of that object from the array, so this assumes that there are only single instances of unique combinations of reaction and user.
Or you could keep it closely to what you have already and use the different form of .and()
...
reactions: r.row('reactions').filter( (item) => {
return r.and(item('reaction').ne(body.reaction), item('user').ne(body.user))
})
...

Related

It is possible to retrieve more than 100 list items Sharepoint with ListItemPicker component?

I'm working with SPFx framework and I'm trying to get all the list items correlated to a specific list. More in details, in my code, I'm using the get() method to retrieve the items, but this function give me only the first 100 elements. This is the piece of code:
async () => {
await this.getConfiguration();
await this.web.lists
.getByTitle(lista_Protocollo)
.get()
.then(async (l) => {
this.setState({ listaProtocolloId: l.Id }),...
Considering I am using the ListItemPicker component, anyone can suggest me a way to overcome the issue?
Thanks
About the mentioned problem, I've know the existence of the getAll() method, but it's not
not suitable in this situation, because I need the Sharepoint list Id. This is an example where I use getAll() method in the solution:
await this.web.lists
.getByTitle(lista_Protocollo)
.items.orderBy("Created")
.getAll()
.then(async (res) => {...
I am not sure why .getAll is not working for you. Anyway, you can also use .top function to overwrite the default limit of 100:
sp.web.lists.getByTitle(lista_Protocollo).items.top(2000).get()
If you want to get both list metadata and list items then you need to make two queries (or a batched query)

GatsbyJS passing user input to GraphQL

I’m looking for examples / tutorials on accepting user input from a form in GatsbyJS and passing that to my GraphQL query.
I can get the user input on submit and also pass variables in when testing graphiql, I just can’t figure out how to combine the two.
My data is stored in Drupal and is a list of recipes.
I’d like the user to be able to type in an ingredient e.g. chicken and then retrieve all of the recipes where chicken is an ingredient.
My query is
query SearchPageQuery($ingredient: String) {
allNodeRecipes(filter: {relationships: {field_ingredients: {elemMatch: {title: {eq: $ingredient}}}}}) {
edges {
node {
id
title
path {
alias
}
relationships {
field_ingredients {
title
}
}
}
}
}
}
If I’m understanding your question correctly, the short answer is you can’t, but another approach might work for you.
Gatsby’s GraphQL queries are run in advance as part of the static build of the site, so the data is part of the client-side JavaScript, but the queries have already been run by that point.
This is the same reason you can’t use JavaScript template literals in a StaticQuery:
// This doesn’t work
let myDynamicSlug = 'home'
return (
<StaticQuery
query={graphql`
query ExampleQuery {
examplePage(slug: { eq: ${myDynamicSlug} }) {
title
}
}
`}
render={data => {
console.log(data)
}}
/>
)
You’ll get an error message explaining “String interpolations are not allowed in graphql fragments.” Further reading: https://github.com/gatsbyjs/gatsby/issues/2293
I had a similar problem recently, and I realised it made a lot of sense why you can’t do this. If you are, ex. generating images using the queries in your GraphQL and things akin to that, you can’t pass in client side variables, because all the “static site” Gatsby operations like handling the images have are already done by that time.
What worked for me was to get the larger portion of data I needed in my query, and find what I needed within. In my previous example, that might mean getting allExamplePages instead of one examplePage, and then finding the myDynamicSlug I needed within it:
// This isn’t exactly how you’d hope to be able to do it,
// but it does work for certain problems
let myDynamicSlug = 'home'
return (
<StaticQuery
query={graphql`
query ExampleQuery {
# You might still be able to limit this query, ex. if you know your item
# is within the last 10 items or you don’t need any items before a certain date,
# but if not you might need to query everything
allExamplePages() {
edges {
node {
title
slug
}
}
}
}
`}
render={data => {
// Find and use the item you want, however is appropriate here
data.edges.forEach(item => {
if (item.node.slug === myDynamicSlug) {
console.log(item)
}
})
}}
/>
)
In your case, that hopefully there is an equivalent, ex. looking something up based on the user input. If you can be more specific about the structure of your data, I’d be happy to try and make my suggestion more specific. Hope that helps!

Apollo client: Making optimistic updates while creation is still in progress

I want to be able to do updates on an object while it is still being created.
For example: Say I have a to-do list where I can add items with names. I also want to be able to edit names of items.
Now say a user with a slow connection creates an item. In that case I fire off a create item mutation and optimistically update my UI. That works great. So far no problem
Now let's say the create item mutation is taking a bit of time due to a slow network. In that time, the user decides to edit the name of the item they just created. For an ideal experience:
The UI should immediately update with the new name
The new name should eventually be persisted in the server
I can achieve #2 by waiting for the create mutation to finish (so that I can get the item ID), then making an update name mutation. But that means parts of my UI will remain unchanged until the create item mutation returns and the optimistic response of the update name mutation kicks in. This means #1 won't be achieved.
So I'm wondering how can I achieve both #1 and #2 using Apollo client.
Note: I don't want to add spinners or disable editing. I want the app to feel responsive even with a slow connection.
If you have access to the server you can implement upsert operations, and you can reduce all queries to the such one:
mutation {
upsertTodoItem(
where: {
key: $itemKey # Some unique key generated on client
}
update: {
listId: $listId
text: $itemText
}
create: {
key: $itemKey
listId: $listId
text: $itemText
}
) {
id
key
}
}
So you will have a sequence of identical mutations differing only in variables. An optimistic response accordingly, can be configured to this one mutation. On the server you need to check if an item with such a key already exists and create or update an item respectively.
Additionally you might want to use apollo-link-debounce to reduce number of requests when user is typing.
I think the easiest way to achieve your desired effect is to actually drop optimistic updates in favor of managing the component state yourself. I don't have the bandwidth at the moment to write out a complete example, but your basic component structure would look like this:
<ApolloConsumer>
{(client) => (
<Mutation mutation={CREATE_MUTATION}>
{(create) => (
<Mutation mutation={EDIT_MUTATION}>
{(edit) => (
<Form />
)}
</Mutation>
)}
</Mutation>
)}
</ApolloConsumer>
Let's assume we're dealing with just a single field -- name. Your Form component would start out with an initial state of
{ name: '', created: null, updates: null }
Upon submitting, the Form would do something like:
onCreate () {
this.props.create({ variables: { name: this.state.name } })
.then(({ data, errors }) => {
// handle errors whichever way
this.setState({ created: data.created })
if (this.state.updates) {
const id = data.created.id
this.props.update({ variables: { ...this.state.updates, id } })
}
})
.catch(errorHandler)
}
Then the edit logic looks something like this:
onEdit () {
if (this.state.created) {
const id = this.state.created.id
this.props.update({ variables: { name: this.state.name, id } })
.then(({ data, errors }) => {
this.setState({ updates: null })
})
.catch(errorHandler)
} else {
this.setState({ updates: { name: this.state.name } })
}
}
In effect, your edit mutation is either triggered immediately when the user submits (since we got a response back from our create mutation already)... or the changes the user makes are persisted and then sent once the create mutation completes.
That's a very rough example, but should give you some idea on how to handle this sort of scenario. The biggest downside is that there's potential for your component state to get out of sync with the cache -- you'll need to ensure you handle errors properly to prevent that.
That also means if you want to use this form for just edits, you'll need to fetch the data out of the cache and then use that to populate your initial state (i.e. this.state.created in the example above). You can use the Query component for that, just make sure you don't render the actual Form component until you have the data prop provided by the Query component.

How to return two one to many relationships in an API response with Laravel controller?

So, I have three models - Events, Groups and Individuals. I'm trying to create an API response that provides a list of groups AND the individuals in each group. I've been able to create a response that provides a list of the groups, but I'm not sure how to also PROPERLY include the individuals of each group.
I thought about just looping through each from the first response and making another query for each, but that seemed like overkill. So, the question is how can I include the Individuals for each Group within the response as well.
I have all three eloquent models defined as such:
Events:
public function groups()
{
return $this->hasMany('App\Group');
}
Groups:
public function event()
{
return $this->belongsTo('App\Event');
}
public function individuals()
{
return $this->hasMany('App\Individual');
}
Individuals:
public function group()
{
return $this->belongsTo('App\Group');
}
Then I have my route:
Route::get('/events/{id}/groups', 'EventsController#groups');
Then that controller has the function to return the list of groups:
public function groups($eventId)
{
$event= Event::find($eventId);
$groups= $event->groups()->paginate();
return $groups;
}
Any help would be greatly appreciated. To clarify, I'd be looking for a response that looks something like:
{
id: 1,
group_name: 'Group Name',
individuals: [ .. array of individuals .. ]
}
Or if someone could give feedback on a better or more standard way to do it, I'd be open to that as well.
You need to use Eager Loading with the with() method:
public function groups($eventId)
{
$event= Event::find($eventId);
$groups= $event->groups()->with('individuals')->paginate();
return $groups;
}
Since you already know event ID, you can use Group model directly and load individuals by using with() method. This code will create just two queries and it's less verbose:
public function groups($eventId)
{
return Group::where('event_id', $eventId)->with('individuals')->paginate(5);
}

Why does Eloquent change relationship names on toArray call?

I'm encountering an annoying problem with Laravel and I'm hoping someone knows a way to override it...
This is for a system that allows sales reps to see inventory in their territories. I'm building an editor to allow our sales manager to go in and update the store ACL so he can manage his reps.
I have two related models:
class Store extends Eloquent {
public function StoreACLEntries()
{
return $this->hasMany("StoreACLEntry", "store_id");
}
}
class StoreACLEntry extends Eloquent {
public function Store()
{
return $this->belongsTo("Store");
}
}
The idea here is that a Store can have many entries in the ACL table.
The problem is this: I built a page which interacts with the server via AJAX. The manager can search in a variety of different ways and see the stores and the current restrictions for each from the ACL. My controller performs the search and returns the data (via AJAX) like this:
$stores = Store::where("searchCondition", "=", "whatever")
->with("StoreACLEntries")
->get();
return Response::json(array('stores' => $stores->toArray()));
The response that the client receives looks like this:
{
id: "some ID value",
store_ac_lentries: [
created_at: "2014-10-14 08:13:20"
field: "salesrep"
id: "1"
store_id: "5152-USA"
updated_at: "2014-10-14 08:13:20"
value: "salesrep ID value"
]
}
The problem is with the way the StoreACLEntries name is mutilated: it becomes store_ac_lentries. I've done a little digging and discovered it's the toArray method that's inserting those funky underscores.
So I have two questions: "why?" and "how do I stop it from doing that?"
It has something in common with automatic changing camelCase into snake_case. You should try to change your function name from StoreACLEntries to storeaclentries (lowercase) to remove this effect.

Resources