Search for documents

View as Markdown

Search is how you find objects in M-Files: there are no folder paths to walk. This recipe finds the documents of one class modified in the last N days, newest first, and stops after a limit.

Calls

SearchObjects with:

Field Value
conditions One SearchConditionArray with the four conditions below; the conditions inside it are ANDed (SearchObjects takes exactly one array)
sorting One SortRule: key 21 (Last modified), options.sort_descending true
limit The maximum number of results
Condition expression type value
Object type is Document status_value, STATUS_TYPE_OBJECT_TYPE CONDITION_TYPE_EQUAL lookup: value list -11, item 0
Not deleted status_value, STATUS_TYPE_IS_DELETED CONDITION_TYPE_EQUAL boolean false
Class property_value, property_def 100 CONDITION_TYPE_EQUAL lookup: value list 1, item = class ID
Modified since property_value, property_def 21 CONDITION_TYPE_GREATER_THAN_OR_EQUAL timestamp

Each result is a SearchResultsItem; object.version_info has the title, version and last_modified_at_utc, object.object_info.obj_id the object's ID. has_more_results is true when the limit cut the results short.

Code

The condition and value builders (is_object_type, is_not_deleted, property_condition, lookup, timestamp and their C# and Go counterparts) are small functions of the samples' helpers (mfiles_values.py, MFilesValues.cs, mfilesclient); each builds one SearchCondition or TypedValue as in the tables above.

Python

since = datetime.now(timezone.utc) - timedelta(days=days)
request = IRPCSearch_pb2.SearchObjectsRequest(
    # One array: all its conditions must match.
    conditions=[structs.SearchConditionArray(value=[
        is_object_type(0),  # documents
        is_not_deleted(),
        # Property 100 "Class" is a lookup into value list 1, the classes.
        property_condition(100, enums.CONDITION_TYPE_EQUAL, lookup(1, class_id)),
        # Property 21 "Last modified" is a timestamp.
        property_condition(21, enums.CONDITION_TYPE_GREATER_THAN_OR_EQUAL,
                           timestamp(since)),
    ])],
    # Newest first. The server sorts all matches, then returns the first `limit`.
    sorting=structs.SearchResultsSorting(rules=structs.SortRuleValueArray(values=[
        structs.SortRule(key=21, options=enums.SortRuleFlags(sort_descending=True))])),
    limit=limit)

search = client.stub(IRPCSearch_pb2_grpc.IRPCSearchStub)
response = search.SearchObjects(request)

Source: python/recipes/search.py

C#

var since = DateTime.UtcNow.AddDays(-days);
var request = new SearchObjectsRequest
{
    // One array: all its conditions must match.
    Conditions =
    {
        new SearchConditionArray
        {
            Value =
            {
                IsObjectType(0),  // documents
                IsNotDeleted(),
                // Property 100 "Class" is a lookup into value list 1, the classes.
                PropertyCondition(100, ConditionType.Equal, Lookup(1, classId)),
                // Property 21 "Last modified" is a timestamp.
                PropertyCondition(21, ConditionType.GreaterThanOrEqual, Timestamp(since)),
            },
        },
    },
    // Newest first. The server sorts all matches, then returns the first `limit`.
    Sorting = new SearchResultsSorting
    {
        Rules = new SortRuleValueArray
        {
            Values = { new SortRule { Key = 21, Options = new SortRuleFlags { SortDescending = true } } },
        },
    },
    Limit = (uint)limit,
};

var search = new IRPCSearch.IRPCSearchClient(connection.CallInvoker);
var response = await search.SearchObjectsAsync(request);

Source: csharp/Recipes/Search.cs

Go

since := time.Now().UTC().AddDate(0, 0, -int(days))
request := &mfiles.SearchObjectsRequest{
	// One array: all its conditions must match.
	Conditions: mfilesclient.AllOf(
		mfilesclient.IsObjectType(0), // documents
		mfilesclient.IsNotDeleted(),
		// Property 100 "Class" is a lookup into value list 1, the classes.
		mfilesclient.PropertyCondition(100, mfiles.ConditionType_CONDITION_TYPE_EQUAL,
			mfilesclient.Lookup(1, classID)),
		// Property 21 "Last modified" is a timestamp.
		mfilesclient.PropertyCondition(21,
			mfiles.ConditionType_CONDITION_TYPE_GREATER_THAN_OR_EQUAL,
			mfilesclient.Timestamp(since)),
	),
	// Newest first. The server sorts all matches, then returns the first `limit`.
	Sorting: mfilesclient.SortBy(21, true),
	Limit:   uint32(limit),
}
search := mfiles.NewIRPCSearchClient(client.Conn)
response, err := search.SearchObjects(ctx, request)
if err != nil {
	return err
}

Source: go/recipes/search/main.go

Output with the defaults (class 1, "Other Document" in the Sample Vault; 30 days) and limit 2:

Documents of class 1 modified since 2026-10-01: 2 (limited to 2; more exist)
  [docs-test] Created by the Python sample 2026-10-31 15:06:31 (ID 629, version 1, modified 2026-10-31 15:06:31 UTC)
  [docs-test] Created by the Python sample 2026-10-31 15:06:29 (ID 628, version 1, modified 2026-10-31 15:06:29 UTC)

The recipe's arguments are the class ID (default 1), the number of days (default 30) and the limit (default 10).

Pitfalls

See also