Maybe have a Unexpected logic in function get_datasets() of DatasetService #8956

Closed
opened 2026-02-21 18:28:50 -05:00 by yindo · 1 comment
Owner

Originally created by @neweyes on GitHub (Mar 3, 2025).

Self Checks

  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

v1.0.0

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

When a request contains both user and search information, querying the user’s datasets appears redundant, as the get_datasets() function checks 'user' before 'search'. Should we instead prioritize checking 'search' first, then decide whether to validate and use user information for dataset queries?

Image

✔️ Expected Behavior

Is that logic right?

if search:
    query.filter(Dataset.name.ilike(f"%{search}%"))
else if tag_ids:
    query by ids
else:
    if not user:
        do something
    else:
        do other things

Actual Behavior

No response

Originally created by @neweyes on GitHub (Mar 3, 2025). ### Self Checks - [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [x] [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:) - [x] Please do not modify this template :) and fill in all the required fields. ### Dify version v1.0.0 ### Cloud or Self Hosted Self Hosted (Docker) ### Steps to reproduce When a request contains both user and search information, querying the user’s datasets appears redundant, as the get_datasets() function checks 'user' before 'search'. Should we instead prioritize checking 'search' first, then decide whether to validate and use user information for dataset queries? ![Image](https://github.com/user-attachments/assets/3baaec33-b314-4522-9c7f-d911db890dd2) ### ✔️ Expected Behavior Is that logic right? ``` if search: query.filter(Dataset.name.ilike(f"%{search}%")) else if tag_ids: query by ids else: if not user: do something else: do other things ``` ### ❌ Actual Behavior _No response_
yindo added the 🐞 buggood first issue labels 2026-02-21 18:28:50 -05:00
yindo closed this issue 2026-02-21 18:28:50 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 3, 2025):

Hey @neweyes! I'm here to help you with any bugs, questions, or contributions. Let's tackle this issue together!

Yes, it is more efficient to prioritize checking the 'search' information before 'user' in the get_datasets() function of the DatasetService class. By doing so, you can reduce the dataset list early, which can then be further filtered based on user permissions. This approach minimizes the number of datasets processed in subsequent steps, improving efficiency.

Here's a refactored version of the get_datasets() function with search prioritized:

@staticmethod
def get_datasets(page, per_page, tenant_id=None, user=None, search=None, tag_ids=None, include_all=False):
    query = Dataset.query.filter(Dataset.tenant_id == tenant_id).order_by(Dataset.created_at.desc())

    if search:
        query = query.filter(Dataset.name.ilike(f"%{search}%"))

    if user:
        # get permitted dataset ids
        dataset_permission = DatasetPermission.query.filter_by(account_id=user.id, tenant_id=tenant_id).all()
        permitted_dataset_ids = {dp.dataset_id for dp in dataset_permission} if dataset_permission else None

        if user.current_role == TenantAccountRole.DATASET_OPERATOR:
            # only show datasets that the user has permission to access
            if permitted_dataset_ids:
                query = query.filter(Dataset.id.in_(permitted_dataset_ids))
            else:
                return [], 0
        else:
            if user.current_role != TenantAccountRole.OWNER or not include_all:
                # show all datasets that the user has permission to access
                if permitted_dataset_ids:
                    query = query.filter(
                        db.or_(
                            Dataset.permission == DatasetPermissionEnum.ALL_TEAM,
                            db.and_(
                                Dataset.permission == DatasetPermissionEnum.ONLY_ME, Dataset.created_by == user.id
                            ),
                            db.and_(
                                Dataset.permission == DatasetPermissionEnum.PARTIAL_TEAM,
                                Dataset.id.in_(permitted_dataset_ids),
                            ),
                        )
                    )
                else:
                    query = query.filter(
                        db.or_(
                            Dataset.permission == DatasetPermissionEnum.ALL_TEAM,
                            db.and_(
                                Dataset.permission == DatasetPermissionEnum.ONLY_ME, Dataset.created_by == user.id
                            ),
                        )
                    )
    else:
        # if no user, only show datasets that are shared with all team members
        query = query.filter(Dataset.permission == DatasetPermissionEnum.ALL_TEAM)

    if tag_ids:
        target_ids = TagService.get_target_ids_by_tag_ids("knowledge", tenant_id, tag_ids)
        if target_ids:
            query = query.filter(Dataset.id.in_(target_ids))
        else:
            return [], 0

    datasets = query.paginate(page=page, per_page=per_page, max_per_page=100, error_out=False)

    return datasets.items, datasets.total

This refactoring ensures that the dataset list is first filtered by the search parameter, potentially reducing the number of datasets that need to be checked for user permissions [1].

To continue talking to Dosu, mention @dosu.


Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Bug Report | Other

@dosubot[bot] commented on GitHub (Mar 3, 2025): <!-- Greeting --> Hey @neweyes! I'm here to help you with any bugs, questions, or contributions. Let's tackle this issue together! <!-- Answer --> Yes, it is more efficient to prioritize checking the 'search' information before 'user' in the `get_datasets()` function of the `DatasetService` class. By doing so, you can reduce the dataset list early, which can then be further filtered based on user permissions. This approach minimizes the number of datasets processed in subsequent steps, improving efficiency. Here's a refactored version of the `get_datasets()` function with `search` prioritized: ```python @staticmethod def get_datasets(page, per_page, tenant_id=None, user=None, search=None, tag_ids=None, include_all=False): query = Dataset.query.filter(Dataset.tenant_id == tenant_id).order_by(Dataset.created_at.desc()) if search: query = query.filter(Dataset.name.ilike(f"%{search}%")) if user: # get permitted dataset ids dataset_permission = DatasetPermission.query.filter_by(account_id=user.id, tenant_id=tenant_id).all() permitted_dataset_ids = {dp.dataset_id for dp in dataset_permission} if dataset_permission else None if user.current_role == TenantAccountRole.DATASET_OPERATOR: # only show datasets that the user has permission to access if permitted_dataset_ids: query = query.filter(Dataset.id.in_(permitted_dataset_ids)) else: return [], 0 else: if user.current_role != TenantAccountRole.OWNER or not include_all: # show all datasets that the user has permission to access if permitted_dataset_ids: query = query.filter( db.or_( Dataset.permission == DatasetPermissionEnum.ALL_TEAM, db.and_( Dataset.permission == DatasetPermissionEnum.ONLY_ME, Dataset.created_by == user.id ), db.and_( Dataset.permission == DatasetPermissionEnum.PARTIAL_TEAM, Dataset.id.in_(permitted_dataset_ids), ), ) ) else: query = query.filter( db.or_( Dataset.permission == DatasetPermissionEnum.ALL_TEAM, db.and_( Dataset.permission == DatasetPermissionEnum.ONLY_ME, Dataset.created_by == user.id ), ) ) else: # if no user, only show datasets that are shared with all team members query = query.filter(Dataset.permission == DatasetPermissionEnum.ALL_TEAM) if tag_ids: target_ids = TagService.get_target_ids_by_tag_ids("knowledge", tenant_id, tag_ids) if target_ids: query = query.filter(Dataset.id.in_(target_ids)) else: return [], 0 datasets = query.paginate(page=page, per_page=per_page, max_per_page=100, error_out=False) return datasets.items, datasets.total ``` This refactoring ensures that the dataset list is first filtered by the `search` parameter, potentially reducing the number of datasets that need to be checked for user permissions <sup>[[1]](https://github.com/langgenius/dify/blob/main/api/services/dataset_service.py)</sup>. <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.* --- <sup>Help Dosu learn! Give it feedback: [Great Response](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=great_response) | [Irrelevant Answer](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=irrelevant_answer) | [Incorrect Sources](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=incorrect_sources) | [Too Verbose](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=hallucination) | [Bug Report](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/28e1969b-6c89-4404-96ce-d1c3da733d5e?feedback_type=other)</sup>
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#8956