0

In my MongoDB collection, I have an array of objects that look like this:

[
  {
    "_id": 123,
    "info": [
      {
        "name": "John",
        "random": ["31", "food", "sleep"]
      }
    ]
  },
  {
    "_id": 234,
    "info": [
      {
        "name": "Amy",
        "random": ["tv", "food", "sleep"]
      }
    ]
  },
  {
    "_id": 345,
    "info": [
      {
        "name": "John",
        "random": ["cars", "tv31", "sleep"]
      }
    ]
  }
]

In C# how would I filter on info where name is John and random contains 31? I also don't know the difference between AnyIn and In.

5
  • When you say "contains" 31, do you mean the string contains the substring 31, or where it contains exactly "31" ? The former won't be an efficient Mongo query unless you have a text index on info.random (and perhaps not even then - I've not really used Mongo text indexes). Commented Aug 15, 2024 at 2:21
  • 1
    data.Where(x => x.info.Any(y => y.name == "John" && y.random.Any(z => z == "31"))); should do the trick. Or if you meant the random strings contains 31 then data.Where(x => x.info.Any(y => y.name == "John" && y.random.Any(z => z.Contains("31")))); should work. Commented Aug 15, 2024 at 3:14
  • Is the info field always an array with a single object like shown (if so, why is it an array)? Commented Aug 15, 2024 at 3:24
  • @user20042973 hey, no it's not always just a single object, but didn't think I needed to add more object for this question. Commented Aug 15, 2024 at 12:50
  • im looking for where name is equal to John and any string in random contains 31 Commented Aug 15, 2024 at 12:52

3 Answers 3

1

The LINQ query (which is covered by other answerers) works and is easier for those unfamiliar with the MongoDB Fluent query.


For those who are looking for MongoDB Fluent syntax:

Assume that your model classes are as below:

public class RootModel
{
   [BsonId]
   public int Id { get; set; }

   public InfoModel[] Info { get; set; }
}

[BsonNoId]
public class InfoModel
{
    public string Name { get; set; }

    public string[] Random { get; set; }
}

You should work with .ElemMatch and .AnyIn:

var filter = Builders<RootModel>.Filter.ElemMatch(x => x.Info,
        Builders<InfoModel>.Filter.Eq(y => y.Name, "John")
        & Builders<InfoModel>.Filter.AnyIn(y => y.Random, new string[] { "31" }));

For the Post Owner's question on the differences between .In and .AnyIn:

In works when your field is a single value and is used to match any element from the provided input array.

AnyIn works when your field is an array and is used to match any element from the provided input array.


Based on your scenario, you will get the syntax error when using .In, for the implementation of In as below:

public FilterDefinition<TDocument> In<TField>(Expression<Func<TDocument, TField>> field, IEnumerable<TField> values)
{
    return In(new ExpressionFieldDefinition<TDocument, TField>(field), values);
}

Unless you are checking the whole Random array that is exactly matched with the array, for example:

random: {
   $in: [['31', 'food', 'sleep'], ...]
}

So this works with In:

Builders<InfoModel>.Filter.In(y => y.Random, 
    new string[][] { new string[] { "31", "food", "sleep" } })

That is another story matching the exact array value compared to the current question which asks for matching any element in the array.

Sign up to request clarification or add additional context in comments.

Comments

0

in C# how would I filter on info where name is "John" and random contains "31"?

You should be able to query the info property of each data item to filter your results, something like:

var results = data.Where(item => 
    item.info.Any(info => 
        info.name == "John" && 
        info.random.Any(random => random == "31")));

2 Comments

Mind though that OP might mean random strings containing 31. That then should include the object with _id = 345 since tv31 contains 31. (See my comment to the question).
@SaniHuttunen maybe, but usually when someone asks about a list containing something, they mean "does it contain this specific thing". Otherwise the question would normally be phrased "where ... random contains an item that contains 31"
0

Following code works.

    public class Item
    {
        [BsonId]  
        [BsonRepresentation(BsonType.Int32)] 
        public int Id { get; set; }
        public IEnumerable<Person> info { get; set; }   
    }

    public class Person
    {
        public string name { get; set; }
        public List<string> random { get;set; }

    }
var filter = Builders<Item>.Filter.Where(item => item.info.Any(info => (info.random.Any(random => random.Contains("31"))) && (info.name == "John")));
var results = collection1.Find(filter).ToList();
var results = collection1.AsQueryable()
                                .Where(item => item.info.Any(info => (info.random.Any(random => random.Contains("31"))) && (info.name == "John")))
                                .ToList();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.