fakemongo / fongo

faked out in-memory mongo for java
Apache License 2.0
523 stars 156 forks source link

Aggregation $cond is causing casting exception #152

Open danieljsun opened 9 years ago

danieljsun commented 9 years ago

The aggregation $cond (see example from https://docs.mongodb.org/manual/reference/operator/aggregation/cond/) is causing the following error:

java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to java.lang.Number at com ... .Group.sum (Group.java:284) ...

sebastienD commented 8 years ago

We have the same problem.

j2rome commented 8 years ago

Hi, I have the same problem with this code. I'm using the latest version 2.0.3.

 BasicDBObject ope = new BasicDBObject()
                .append("$group",
                        new BasicDBObject()
                        .append("_id", "$toto")
                        .append("nbReached", new BasicDBObject("$sum",  
                                new BasicDBObject("$cond",
                                        new Object[]{new BasicDBObject("$eq", new Object[]{"$toto.status", "SUCCESS"}), 1, 0}
                                )
                        )));
twillouer commented 8 years ago

Ok, I see the problem. It's a big change, but necessary. I'll keep you in touch

bsautel commented 7 years ago

Any news regarding this issue?

I am working on an aggregation that works in MongoDB but not in Fongo. It sounds like the $cond field is totally ignored by Fongo version 2.0.9.

bsautel commented 7 years ago

@twillouer here is a unit test with an aggregation that works with MongoDB and not with Fongo. It seems that the issue comes from the $cond operator.

import com.github.fakemongo.Fongo;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.StreamSupport;

import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;

public class FongoTest {
    private MongoCollection<Document> testCollection;

    @Before
    public void setUp() {
        Fongo fongo = new Fongo("test");
        MongoDatabase database = fongo.getDatabase("test");
        testCollection = database.getCollection("likes");
        // With MongoDB
        // MongoDatabase database = new MongoClient("localhost").getDatabase("fongo");
        // testCollection = database.getCollection("likes");
        // testCollection.drop();
        // This collection stores likes. It contains documents telling who (userId) likes what (reference)
        testCollection.insertOne(new Document("_id", new Document().append("userId", "user1").append("reference", "reference1")));
        testCollection.insertOne(new Document("_id", new Document().append("userId", "user2").append("reference", "reference1")));
        testCollection.insertOne(new Document("_id", new Document().append("userId", "user2").append("reference", "reference2")));
    }

    @Test
    public void shouldCountLikesByReference() {
        // This request counts how many users like some references and tell whether the current user likes each of them (iLike field) 
        AggregateIterable<Document> aggregate = testCollection.aggregate(Arrays.asList(
                new Document("$match", new Document("_id.reference", new Document("$in", Arrays.asList("reference1", "reference2")))),
                new Document("$project", new Document().append("reference", "$_id.reference").append("iLike", new Document("$cond", new Document().append("if", new Document("$eq", Arrays.asList("$_id.userId", "user1"))).append("then", 1).append("else", 0)))),
                new Document("$group", new Document().append("_id", "$reference").append("count", new Document().append("$sum", 1)).append("iLike", new Document("$max", "$iLike"))),
                new Document("$project", new Document().append("count", 1).append("iLike", new Document("$cond", new Document().append("if", new Document("$eq", Arrays.asList(1, "$iLike"))).append("then", true).append("else", false))))
        ));

        Set<Document> result = StreamSupport.stream(aggregate.spliterator(), false).collect(toSet());

        assertThat(result).containsOnly(
                new Document().append("_id", "reference1").append("count", 2).append("iLike", true),
                new Document().append("_id", "reference2").append("count", 1).append("iLike", false)
        );
    }
}
twillouer commented 7 years ago

Yes, sorry, it's a very difficult change and I have not working on it..

Thanks for the unit test, I will try to spend time on it

shubharora commented 7 years ago

@twillouer Did you find any fix for that $cond issue in fongo? I am also using aggregation with $cond operator, that works fine with Mongo, but test case fail as it uses fongo, which kinda does not support this.