Put all the model matrix in an array (in an SSBO or a Uniform buffer) GLSL will provide a gl_InstanceIndex variable to the shader that will start at the base_instance value you provide to the draw elements function.
mat4 model = ssbo_model_mats[gl_instanceIndex];
After each instance the value will be incremented automatically. The biggest challenge becomes grouping the object model matrices so they are lined up all nice and neat for indexing the model matrix.
A natural extension of this is to run a compute shader that can update the matrices for physics, rotation, collision, whatever, then rearrange them for drawing those visible with one or two draw calls.
There is even an indirect version:
glDrawElementsIndirect(...); // and several others
that allows the buffer the data is sitting in to be specified so that virtually the entire draw call can be setup on the GPU using compute shaders.
Combined with "bindless" rendering techniques this can be a very powerful method.