Usability of collection management

I’m creating a large complex mechanical object with many components (300+) and trying to organize them all in collections as I go — and really struggling with usability issues. To the point that I’m wondering if I’m doing it wrong, or everyone else has some magic addon, or no one actually uses collections.

Example actions I find difficult that would be helpful single actions:

  • move all objects to their parent’s (primary) collection
  • move all selected objects to the active object’s collection
  • create a new subcollection from the selected objects (in outliner, or 3D view)
  • search for collection by name when I hit ‘M’ (similar to adding a modifier popup)

There’s also of course the strange behavior where Cmd-G creates a “hidden” collection that isn’t in the scene collection (I understand the historical context for this, but is it actually useful behavior at this point?).

A major complexity here is that objects can be in more than one collection; however, in practice, I do that rarely (is that what I’m doing wrong?), so even if the above operations only worked when an object was in a single collection that would be a big win. I’ve tried the built-in Collection Manager add-on, which helps somewhat (I can search for collections when I hit ‘M’), but it’s still tedious and requires clicks.

What am I doing wrong? Any tips and tricks?

You might find this addon to be helpful:

Yeah, I’ve seen that one.

I’m open to it if the vanilla experience is really just this challenging, I guess, but it seems like it shouldn’t be!

With the help of Gemini I wrote a quick addon to do at least the move-to-active-object’s-collection, and it has already been extremely useful.

Included here if anyone else finds it useful

import bpy

class MoveToActiveCollectionOperator(bpy.types.Operator):
    """Move selected objects to the collection of the active selected object"""
    bl_idname = "object.move_to_active_object_collection"
    bl_label = "Move to Active Object Collection"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        active_object = context.active_object

        if not active_object:
            self.report({'ERROR'}, "No active object")
            return {'CANCELLED'}

        # Check if the active object is in more than one collection
        if len(active_object.users_collection) != 1:
            self.report({'ERROR'}, "Active object is in multiple collections.  Please select an object in exactly one collection.")
            return {'CANCELLED'}

        active_collection = active_object.users_collection[0]  # Get the first collection the active object is in

        selected_objects = context.selected_objects
        moved = 0
        for obj in selected_objects:
            if obj != active_object:  # Avoid adding the active object itself
                if len(obj.users_collection) != 1:
                    self.report({'ERROR'}, "Target object is in multiple collections.  Please select objects in exactly one collection.")
                    return {'CANCELLED'}
                if obj.users_collection[0] != active_collection:
                    moved += 1

        bpy.ops.ed.undo_push()
        for obj in selected_objects:
            if obj != active_object:  # Avoid adding the active object itself
                obj.users_collection[0].objects.unlink(obj)  # Remove from current collection
                active_collection.objects.link(obj)  # Add to the active collection

        self.report({'INFO'}, "Moved {0} objects to collection '{1}'".format(
            moved, active_collection.name))
        return {'FINISHED'}


class OBJECT_MT_custom_menu(bpy.types.Menu):
    bl_label = "Custom Menu"

    def draw(self, context):
        layout = self.layout
        layout.operator(MoveToActiveCollectionOperator.bl_idname, text="Move to Active Object Collection",
                        icon="MODIFIER")


def register():
    bpy.utils.register_class(MoveToActiveCollectionOperator)
    bpy.utils.register_class(OBJECT_MT_custom_menu)

    # Add the menu to the object context menu
    bpy.types.VIEW3D_MT_object_context_menu.append(OBJECT_MT_custom_menu.draw)


def unregister():
    # Remove the menu from the object context menu
    bpy.types.VIEW3D_MT_object_context_menu.remove(OBJECT_MT_custom_menu.draw)

    bpy.utils.unregister_class(OBJECT_MT_custom_menu)
    bpy.utils.unregister_class(MoveToActiveCollectionOperator)


if __name__ == "__main__":
    register()

Hello ! Yeah it looks like you could use a few extra command, sound easy to script for the most part… I think most people uses collections to organize their work, personally I didn’t had issue with built in command and didn’t needed anything more, but in the meantime it’s rare that I have a lot of objects to manage. If I had 300 objects I would probably try to have something like 10/15 collections so it’s easy to find where things should go. 30 objects per collections starts to feels like a lot but it’s manageable…

And indeed I rarely share objects between collection at first, but it’s very useful for rendering ( multiple layers ) or when using geometry nodes…