Apollo query has the wrong data from cache in my react app.
If I set query's fetchPolicy to 'network-only', everything work properly.
So I think it is a cache problem.
I have been working hard trying to solve the problem and see articles about apollo cache, but I still can't solve the problem.
Here are my results after querying:
parameter memberId is null (result is correct)
[
{
"id": 87,
"totalQuantity": 12,
"Orders": [
{
"id": 1,
"quantity": 11,
"Member": {
"id": 1,
"name": "A"
}
},
{
"id": 28,
"quantity": 1,
"Member": {
"id": 9,
"name": "B"
}
}
]
},
{
"id": 88,
"totalQuantity": 1,
"Orders": [
{
"id": 2,
"quantity": 1,
"Member": {
"id": 1,
"name": "A"
}
}
]
}
]
parameter memberId is 9 (result is correct)
[
{
"id": 87,
"totalQuantity": 1,
"Orders": [
{
"id": 28,
"quantity": 1,
"Member": {
"id": 9,
"name": "B"
}
}
]
}
]
parameter memberId is 1 (result is correct)
[
{
"id": 87,
"totalQuantity": 11,
"Orders": [
{
"id": 1,
"quantity": 11,
"Member": {
"id": 1,
"name": "A"
}
}
]
},
{
"id": 88,
"totalQuantity": 1,
"Orders": [
{
"id": 2,
"quantity": 1,
"Member": {
"id": 1,
"name": "A"
}
}
]
}
]
but when I back to parameter is null the result is wrong
[
{
"id": 87,
"totalQuantity": 11,
"Orders": [
{
"id": 1,
"quantity": 11,
"Member": {
"id": 1,
"name": "A"
}
}
]
},
{
"id": 88,
"totalQuantity": 1,
"Orders": [
{
"id": 2,
"quantity": 1,
"Member": {
"id": 1,
"name": "A"
}
}
]
}
]
Member B (id = 9) is disappear..
and I back to parameter is 9 (result is wrong)
[
{
"id": 87,
"totalQuantity": 11,
"Orders": [
{
"id": 1,
"quantity": 11,
"Member": {
"id": 1,
"name": "A"
}
}
]
}
]
I get the Member A's data instead of Member B
Can someone help me? Thanks
My client configuration (cache is InMemoryCache)
const client = new ApolloClient({
link: ApolloLink.from([
httpLink,
]),
cache,
dataIdFromObject: o => ${o.id}${o.__typename},
});
I use queryHook to wrap my component
const queryHook = graphql(FETCH_ORDER_GROUP_SHIPMENT_LIST, {
options: ownProps => ({
variables: {
memberId: ownProps.options.memberId || null,
},
}),
props: ({
data: {
orderGroupShipmentList,
},
}) => ({
orderGroupShipmentList: orderGroupShipmentList || [],
});
Also I use Query tag(other data) to wrap my content
and its parameter is memberId as well.
the structure like this
<Query
variables={{ memberId: options.memberId || null }}
query={FETCH_MEMBER_LIST_QUERY}>
content that use orderGroupShipmentList and memberList
</Query>
I don't know if this is specific enough
Let me know if this is not specific enough
Thanks
2019-09-16
For those who facing the same problem:
https://kamranicus.com/posts/2018-03-06-graphql-apollo-object-caching
You need to have different ids for that type on the returned results for your query. For example, you have different results for id 87 based on memberId, so the cache will be overwritten by your second query and since apollo does not refetch queries already made by default it will continue to look at the overwritten result.
#Anymore - can we see you FETCH_MEMBER_LIST_QUERY code? Are you fetching id's for all the data? Without the ids it won't be able to match relations.
Have you tried using Apollo Client DevTools - they will let you easily view the contents of the cache. It can be found on GitHub here and the Chrome Webstore here
Using this you will be able to see if the item is being cached correctly.
Related
my data structure is and products elements all tags in empty
I need to add a value to mongo db inner object with array element without looking at other value. Can some one advice to do this.
[
{
"item": "journal",
"id": 11,
"products": [
{
"id": 3,
"name": "p one",
"tags": []
}
]
},
{
"item": "notebook",
"id": 14,
"products": [
{
"id": 4010,
"name": "item-five",
"tags": []
}
]
}
]
and I want to add tag in products elements with match product id '4010', so the expected response should be like
[
{
"item": "journal",
"id": 11,
"products": [
{
"id": 3,
"name": "p one",
"tags": []
}
]
},
{
"item": "notebook",
"id": 14,
"products": [
{
"id": 4010,
"name": "item-five",
"tags": [
{
"id": 21,
"key": "tag-one",
"name": "tag-one",
}
]
}
]
}
]
You should look at arrayFilter option https://www.mongodb.com/docs/v6.0/reference/operator/update/positional-filtered/#update-all-documents-that-match-arrayfilters-in-an-array
Something like this might do the trick.
db.collection.updateMany(
{ },
{ $push: { "products.$[x].tags": {
"id": 21,
"key": "tag-one",
"name": "tag-one",
} } },
{ arrayFilters: [{ "x.id": 4010 }] }
);
Currently I have a many-to-many relationship between entities. A Transaction contains many persons and a Person contains many Transactions. I'm writing a query to filter out transactions so that the transactions contains the person's name. The problem I'm running into is when I filter based on name, it removes the other Person from the transaction.
Example:
{
"id": 1,
"txnDate": "2021-03-09T12:40:26.000Z",
"persons": [
{
"id": 1,
"name": "Bill"
},
{
"id": 2,
"name": "Jen"
}
]
},
{
"id": 2,
"txnDate": "2021-03-09T12:40:26.000Z",
"persons": [
{
"id": 2,
"name": "Jen"
},
{
"id": 3,
"name": "Bob"
}
]
},
My current query is:
query.leftJoinAndSelect('transaction.persons', 'persons')
.andWhere('persons.name = :name', { name });
where name is a string. If I set name= Bill it results in:
{
"id": 1,
"txnDate": "2021-03-09T12:40:26.000Z",
"persons": [
{
"id": 1,
"name": "Bill"
},
]
},
However, I want it so that when I query by name it would result in:
{
"id": 1,
"txnDate": "2021-03-09T12:40:26.000Z",
"persons": [
{
"id": 1,
"name": "Bill"
},
{
"id": 2,
"name": "Jen"
}
]
},
I'm really stuck and I would love any ideas on how to solve this
Current Stack: Nodejs, TypeORM, TypeScript
I have been asked in an interview to mutate the array of objects in such a way that the data appears in the following manner
[
{
"companyName": "ABC",
"members": [
{
"id": 13121212,
"firstName": "Ray",
"lastName": "Fernandis",
"points": 1800,
"position": 1
},
{
"id": 13131313,
"firstName": "Carrie",
"lastName": "Yoda",
"points": 1200,
"position": 2
}
]
}]
and the sample data was given below.
[
{
"communityName": "ABC",
"lastUpdateTimestamp": {
"date": {
"year": 2020,
"month": 10,
"day": 7
},
"time": {
"hour": 18,
"minute": 6,
"second": 5,
"nano": 536529000
}
},
"data": {
"listChannelsData": [
{
"channelId": 1234,
"channelName": "BCD",
"members": [
{
"id": 13121212,
"firstName": "Ray",
"lastName": "Fernandis",
"points": 1800,
"position": 1
}
]
}
]
}
},
{
"communityName": "DEF",
"lastUpdateTimestamp": {
"date": {
"year": 2020,
"month": 10,
"day": 7
},
"time": {
"hour": 18,
"minute": 6,
"second": 21,
"nano": 47894000
}
},
"data": {
"listChannelsData": [
{
"channelId": 3421,
"channelName": "GHI",
"members": [
{
"id": 13121212,
"firstName": "Nicholas",
"lastName": "Xin",
"points": 800,
"position": 2
},
{
"id": 13131313,
"firstName": "Carrie",
"lastName": "Yoda",
"points": 1000,
"position": 1
}
]
}
]
}
}
]
The agenda for me was to print the derived json from sample json and I could only figure out this much code which was a courtesy of stackoverflow
function dictionary(data) {
var map = {};
data.forEach(item => {
if (!Array.isArray(map[item.companyName])) {
map[item.companyName] = [item.data.listChannelsData];
} else {
map[item.communityName].push(item.data.listChannelsData);
}
});
return map;
}
console.log(dictionary(data));
But now when I try to pick up the data for the member using another foreach loop, I'm not able to access the data for members. Can anyone help me with the part where I can successfully access the member array and print the company name along side it
Try this code
var newArray = []
data.map((item, index) => {
newArray[index] = {companyName : item.communityName}
newArray[index].members = item.data.listChannelsData[0].members
})
data is the given data.
I have a document in the form of:
curl -XPOST localhost:9200/books/book/1 -d '{
"user_id": 1,
"pages": [ {"page_id": 1, "count": 1}, {"page_id": 2, "count": 3}]
}
Now lets say the user reads page 1 again, so I want to increment the count. The document should become:
{
"user_id": 1,
"pages": [ {"page_id": 1, "count": 2}, {"page_id": 2, "count": 3}]
}
But how do you do this update of an element of a list using an if variable?
An example of a simple update in Elasticsearch is as follows:
curl -XPOST localhost:9200/books/book/2 -d '{
"user_id": 1,
"pages": {
"page_1": 1,
"page_2": 2
}
}'
curl -XPOST localhost:9200/books/book/2/_update -d '
{
"script": "ctx._source.pages.page_1+=1"
}'
The document now becomes:
{
"user_id": 1,
"pages": {
"page_1": 1,
"page_2": 2
}
However this more simple format of a doc looses stating the page_id as a field, so the id itself acts as the field. Similarly the value associated to the field has no real definition. Thus this isn't a great solution.
Anyway, would be great to have any ideas on how to update the array accordingly or any ideas on structuring of the data.
Note: Using ES 1.4.4, You also need to add script.disable_dynamic: false to your elasticsearch.yml file.
Assuming I'm understanding your problem correctly, I would probably use a parent/child relationship.
To test it, I set up an index with a "user" parent and "page" child, as follows:
PUT /test_index
{
"settings": {
"number_of_shards": 1
},
"mappings": {
"user": {
"_id": {
"path": "user_id"
},
"properties": {
"user_id": {
"type": "integer"
}
}
},
"page": {
"_parent": {
"type": "user"
},
"_id": {
"path": "page_id"
},
"properties": {
"page_id": {
"type": "integer"
},
"count": {
"type": "integer"
}
}
}
}
}
(I used the "path" parameter in the "_id"s because it makes the indexing less redundant; the ES docs say that path is deprecated in ES 1.5, but they don't say what it's being replaced with.)
Then indexed a few docs:
POST /test_index/_bulk
{"index":{"_type":"user"}}
{"user_id":1}
{"index":{"_type":"page","_parent":1}}
{"page_id":1,"count":1}
{"index":{"_type":"page","_parent":1}}
{"page_id":2,"count":1}
Now I can use a scripted partial update to increment the "count" field of a page. Because of the parent/child relationship, I have to use the parent parameter to tell ES how to route the request.
POST /test_index/page/2/_update?parent=1
{
"script": "ctx._source.count+=1"
}
Now if I search for that document, I will see that it was updated as expected:
POST /test_index/page/_search
{
"query": {
"term": {
"page_id": {
"value": "2"
}
}
}
}
...
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test_index",
"_type": "page",
"_id": "2",
"_score": 1,
"_source": {
"page_id": 2,
"count": 2
}
}
]
}
}
Here is the code all in one place:
http://sense.qbox.io/gist/9c977f15b514ec251aef8e84e9510d3de43aef8a
In the following records I want to get item_details where type is "system" and id is "7634e9639f5c25f2434b72d8a"
var operator = {
'item_details': {
$elemMatch: {
type: 'custom'
}
}
}
var query = {
_id : "7634e9639f5c25f2434b72d8a"
};
req.db.collection('products').find(query, operator).toArray(function (err, result) {
if(err)throw err;
console.log(result);
});
It is returning only the first element. But need to get the all records which matches the query and projection. Below is the sample data from which I want to query.
[
{
"_id": "7634e9639f5c25f2434b72d8a",
"item_details": [
{
"quantity": 1,
"sub_total": 1201,
"type": "system"
},
{
"quantity": 19,
"sub_total": 140,
"type": "custom"
},
{
"quantity": 81,
"sub_total": 130,
"type": "custom"
},
{
"quantity": 71,
"sub_total": 90,
"type": "system"
}
]
},
{
"_id": "564e9639f5c25f2434b72d8a",
"item_details": [
{
"quantity": 1,
"sub_total": 101,
"type": "system"
},
{
"quantity": 9,
"sub_total": 40,
"type": "custom"
},
{
"quantity": 8,
"sub_total": 30,
"type": "custom"
},
{
"quantity": 7,
"sub_total": 60,
"type": "system"
}
]
}
]
$elemmatch will only give you the 1st element of the array (in subdocuments).
see below
http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/
So we could rather use the dot notation to get what you want.
req.db.collection('products').find({"_id": "7634e9639f5c25f2434b72d8a", "item_details.type": "custom"}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
});