2

The docs says I can use :

Find(x => x.FavoriteNumbers.Length == 3);

If I write:

await col.Find(f=>f.AuthType > 2).ToListAsync()

I do get the expected result because all AuthType are greater than 2.

enter image description here

But now, let's say that I want to filter all records with Id.Length>2:

await col.Find(f=>f.Id.Length>2).ToListAsync();

This returns 0 records.

Question:

How can I get all the records with Id's Length >2 ?

I've already read this question , but with no answer and the dup is not in c#

mickl
  • 48,568
  • 9
  • 60
  • 89
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • I don't know mongo, just cardboard analysing: Is ID a string, byte array etc, or something else that actually has a .Length property? What if it's a Guid or something that doesn't have a Length? How to format it to a string so you can tell how long it is? – Caius Jard Jul 13 '19 at 09:42
  • @CaiusJard It's `Id.ToString().Length` . Id here is a string. not a guid. this is not how guid looks like – Royi Namir Jul 13 '19 at 09:43

2 Answers2

2

In Visual Studio you can write below line of code and try to inspect it by hovering:

var query = await col.Find(f=>f.Str.Length>2)

What happens is that MongoDB will transalte it into regular expression like {find({ "Str" : /^.{3,}$/s })} and this regex gets executed on the database side. Nothing unexpected. The problem occurs when you change Str into Id which gets translated into:

{find({ "_id" : /^.{3,}$/s })}

and you get no result as your field's name is still Id. The reason why it's happening is described here. So MongoDB driver by convention infers that field named Idshould be translated into _id. To fix that you can explicitly specify on your data model which field should be considered as _id using BsonId attribute:

public class ModelClass
{
    [BsonId]
    public ObjectId RealId { get; set; }
    public string Id { get; set; }
}

EDIT:

To apply type conversion (int -> string) you have to rely on $toString operator introduced in MongoDB. The idea is simple: you add new field using $addFields and then run $strLenCP on it to verify string length. Unfortunately there's no easy way to do it in C# using strongly typed way so you can use BsonDocument class which lets you use strings as Aggregation Pipeline definition:

var q = Col.Aggregate()
            .AppendStage<BsonDocument>(BsonDocument.Parse("{ $addFields: { AuthTypeInt: { $toString: \"$AuthType\" } } }"))
            .Match(BsonDocument.Parse("{ $expr: { $gt: [ { \"$strLenCP\": \"$AuthTypeInt\" }, 2 ] } }"));

var data = await q.ToListAsync();

The code looks ugly but it should be a way faster than running plain JavaScript (more here)

mickl
  • 48,568
  • 9
  • 60
  • 89
  • `await col.Find(f=>f.AuthType.ToString().Length==3).ToListAsync()` failes on `{document}{authType}.ToString().Length is not supported` – Royi Namir Jul 13 '19 at 11:32
  • @RoyiNamir don't use `ToString()` there's no way to translate that operator into something on database side. Or there is a way but it's not implemented in the driver yet. Just run it on a field that's already defined as string both on DB and in C# class – mickl Jul 13 '19 at 11:34
  • @RoyiNamir two different things: for strings it works as the documentation says with the caveat for conventions (field named `Id`). For ints it won't because you're trying to convert types (using `.ToString()`) which is not implemented in C# driver (was introduced in MongoDB 4.0). Can't you just check `AuthType > 99` ? – mickl Jul 13 '19 at 11:38
  • First of all , thank you for your help. I'm learning mongo , and I wanted to know by a simple tests how can I achieve `this.authType.toString().length>2` - in a C# way. Sure I can check its value. But tomorrow i'd want to filter by its length. Hence my question. How can I do `this.authType.toString().length>2` in C# way ? BTW i've posted an answer but I don't like JS in C#. – Royi Namir Jul 13 '19 at 11:40
  • @RoyiNamir there is a way to do that in MongoDB 4.0 or newer but the code won't be so nice as you expect. Is that fine for you (MongoDB version) ? – mickl Jul 13 '19 at 11:43
  • Sure. I'd be happy to see the code I have the latest version I think. I've installed it yesterday from the official site - locally) – Royi Namir Jul 13 '19 at 11:44
  • btw - I've created `RealId` - but it doesn't have `Length` https://i.imgur.com/8231VWX.jpg – Royi Namir Jul 13 '19 at 11:54
  • Modified my answer. Answering your question: `Length` is available on `strings`, `RealId` was supposed to be an `ObjectId` and represent `_id` field which has to occur in your data anyway – mickl Jul 13 '19 at 12:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/196413/discussion-between-royi-namir-and-mickl). – Royi Namir Jul 13 '19 at 12:05
  • Can u plz have a look at https://stackoverflow.com/questions/65503195/cannot-use-mongos-filter-with-datetime-and-bsonstring ? – Royi Namir Dec 30 '20 at 07:05
0

I've managed to do it in a very ugly way, involving JS:

var ll=new BsonDocument("$where", new BsonJavaScript("function() { return this.authType.toString().length>2; }"));

var t2 = await col.Find(ll).ToListAsync();

enter image description here

What is the C# equivalent solution?

Royi Namir
  • 144,742
  • 138
  • 468
  • 792