Jaydendev
Jaydendev

Reputation: 163

includes() returns false when array contains value

I have an array with objects inside. I get the array from my firestore database. When I get the array, I check if my user has any of the objects. When I check this using includes() I get false as a return, but the array clearly has the object. What can be the issue?

Check:

            const querySnapshot = await getDocs(colRef);

            querySnapshot.forEach(async(badge) => {
                console.log(userData.obtainedBadges)
                if(!userData.obtainedBadges.includes(badge.data())){                        
                    console.log(badge.data())
                    console.log("not includes")
                    setObtainableBadges(prev => {
                        return [...prev, badge.data()]
                     })
                } else {
                    console.log("includes")
                    setUserBadges(prev => {
                        return [...prev, badge.data()]
                     })
                }
            })

For example one of the objects I check( badge.data() ) :

Object { id: 1, desc: "Play 5 games.", type: "games", reward: 10, condition: 5, img: "/trophies/firsttrophy.png", name: "The First Games" }

querySnapshot Array:

Array(9) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…} ]
​
0: Object { img: "/trophies/firsttrophy.png", type: "games", name: "The First Games", … }
​
1: Object { id: 2, type: "games", name: "The Beginner", … }
​
2: Object { name: "The Big Brain", id: 50, type: "games", … }
​
3: Object { condition: 50, id: 4, desc: "Play 50 games.", … }
​
4: Object { name: "Noob", reward: 10, img: "/trophies/noobmedal.png", … }
​
5: Object { id: 6, reward: 10, desc: "Reach a minimum high score of 2000.", … }
​
6: Object { condition: 3000, desc: "Reach a high score of 3000.", name: "Unstoppable", … }
​
7: Object { desc: "Reach a score of 0 in any gamemode.", id: 9, reward: 25, … }
​
8: Object { type: "easteregg", condition: "easteregg", desc: "Find an easter egg!", … }
​
length: 9
​
<prototype>: Array []

You can see, that my object is the first element in the array. But for some reason, includes() returns false.

Upvotes: 1

Views: 1696

Answers (3)

Lajos Arpad
Lajos Arpad

Reputation: 76464

includes searches a value inside an object. Yet, similar objects are not the same, just like twins are different persons. Proof:

console.log({} === {});

So, since includes does not search for similar objects, but for the specific object, your

if (!userData.obtainedBadges.includes(badge.data())) {

is incorrect. Instead, you will need to .filter() yourself, like:

if (userData.obtainedBadges.filter(item => item.id === badge.data().id).length === 0) {

Which searches a match for badge.data() inside userData.obtainedBadges by id, retrieves an array, whose size is 0 if no such match was found.

Upvotes: 0

Eduard Lavrov
Eduard Lavrov

Reputation: 1

I just fixed it by my own function instead of .includes():

function areIdentical(actualValue, expectedValue) {
    let actualValueKeys = Object.keys(actualValue);
    let expectedValueKeys = Object.keys(expectedValue);

    if (actualValueKeys.length != expectedValueKeys.length) {
        return 0;
    } else {
        let result = 0;
        actualValueKeys.forEach(x => {
            if (actualValue[x] == expectedValue[x]) result += (1 / actualValueKeys.length) * 100;
        });

        return result;
    }
}

and You can use: (yourArray.filter(x => areIdentical(x, value) > 99).length > 0) ? true : false

Upvotes: -1

Jip Helsen
Jip Helsen

Reputation: 1346

When you compare two objects in JavaScript it is not enough that their keys and values match. All objects have internal ids and therefor two objects or arrays with the same keys and values will in a regular comparison like == still return false. See example :

const object1 = {test:'test'}
const object2 = {test:'test'}
console.log(object1 == object2)
The same goes for arrays, maps, sets and all non-primitive values in JavaScript. It is however possible to compare objects, arrays non-primitives but only by comparing all their properties. This can get really complicated, as objects can contain other non-primitives and to make a general use function you would need to make a recursive function that can handle any JavaScript type, which would be total overkill for you situation. In a case like this one you should check on a unique value, id for example, instead of comparing the whole objects. Something like this :

const badge_in_user_data = userData.obtainedBadges.some(badge => badge.id == badge.data().id)

Upvotes: 2

Related Questions