0

I have implemented models for User-Group relationship, where one User can be a member and owner of one or more Groups and where one Group can have one or more owners and one or more members.

Now, the problem is User.owned_groups returns only 1 Group even if the user owns more than 1 group.

I am facing the same issue with User.member_groups, Group.owners and Group.members. All methods are returning only 1 record.

Below are the models and the values in the database.

Models: -

require 'rubygems'
require 'data_mapper'
require 'dm-types'

module Contacts
  class User
    include DataMapper::Resource

    property :id,         Serial,   :key => true
    property :username,   String,   :required => true, :unique => true

    has n, :group_owners, :child_key => [:owned_group_id]
    has n, :owned_groups, 'Group', :through => :group_owners

    has n, :group_members, :child_key => [:member_group_id]
    has n, :member_groups, 'Group', :through => :group_members

    #------------------------------------------#
    # args should be an array of hashes        #
    # Example: args = [{:id => 1},{:id => 2}]  #
    #------------------------------------------#
    def self.get_users args
      users = Array.new
      args.each do |user|
        all_users = User.all(user)
        all_users.each do |u|
          user_hash = u.attributes

          user_hash[:owned_groups] = Array.new
          u.owned_groups.each do |owned_group|
            g = owned_group.attributes
            user_hash[:owned_groups].push g
          end

          user_hash[:member_groups] = Array.new
          u.member_groups.each do |member_group|
            g = member_group.attributes
            user_hash[:member_groups].push g
          end

          users.push user_hash
        end
      end
      return users
    end
  end

  class Group
    include DataMapper::Resource

    property :id,   Serial, :key => true
    property :name, String, :required => true, :unique => true

    has n, :group_owners, :child_key => [:owner_id]
    has n, :owners, 'User', :through => :group_owners

    has n, :group_members, :child_key => [:member_id]
    has n, :members, 'User', :through => :group_members

    #------------------------------------------#
    # args should be an array of hashes        #
    # Example: args = [{:id => 1},{:id => 2}]  #
    #------------------------------------------#
    def self.get_groups args
      groups = Array.new

      args.each do |group|
        all_groups = Group.all(group)
        all_groups.each do |g|
          group_hash = g.attributes

          group_hash[:owners] = Array.new
          g.owners.each do |owner|
            u = owner.attributes
            group_hash[:owners].push u
          end

          group_hash[:members] = Array.new
          g.members.each do |member|
            u = member.attributes
            group_hash[:members].push u
          end
          groups.push group_hash
        end
      end
      return groups
    end
  end

  class GroupOwner
    include DataMapper::Resource

    property :id, Serial, :key => true
    belongs_to :owner, 'User'
    belongs_to :owned_group, 'Group'
  end

  class GroupMember
    include DataMapper::Resource

    property :id, Serial, :key => true
    belongs_to :member, 'User'
    belongs_to :member_group, 'Group'
  end
end

MySQL: -

mysql> select * from contacts_users;
+----+-----------+
| id | username  |
+----+-----------+
|  1 | testuser1 |
|  2 | testuser2 |
+----+-----------+

mysql> select * from contacts_groups;
+----+------------+
| id | name       |
+----+------------+
|  1 | testgroup1 |
|  2 | testgroup2 |
+----+------------+
2 rows in set (0.00 sec)


mysql> select * from contacts_group_owners;
+----+----------+----------------+
| id | owner_id | owned_group_id |
+----+----------+----------------+
|  1 |        1 |              1 |
|  2 |        2 |              1 |
|  3 |        1 |              2 |
|  4 |        2 |              2 |
+----+----------+----------------+
4 rows in set (0.00 sec)

mysql> select * from contacts_group_members;
+----+-----------+-----------------+
| id | member_id | member_group_id |
+----+-----------+-----------------+
|  1 |         1 |               1 |
|  2 |         2 |               1 |
|  3 |         1 |               2 |
|  4 |         2 |               2 |
+----+-----------+-----------------+
4 rows in set (0.00 sec)

In the debug mode, this is the MySQL query generated for User.owned_groups:

    SELECT 
      `contacts_groups`.`id`, 
      `contacts_groups`.`name`, 
      `contacts_groups`.`created_at`, 
      `contacts_groups`.`updated_at` 
   FROM `contacts_groups` 
   INNER JOIN `contacts_group_owners` 
      ON `contacts_groups`.`id` = `contacts_group_owners`.`owned_group_id` 
   INNER JOIN `contacts_users` 
      ON `contacts_group_owners`.`owned_group_id` = `contacts_users`.`id` 
   WHERE `contacts_group_owners`.`owned_group_id` = 1 
   GROUP BY 
      `contacts_groups`.`id`, 
      `contacts_groups`.`name`, 
      `contacts_groups`.`created_at`, 
      `contacts_groups`.`updated_at` 
   ORDER BY `contacts_groups`.`id

Versions:

Ruby - 2.0.0-p0

Sinatra - 1.3.4

DataMapper - 1.2.0

Am I missing out something trivial?

Thanks in advance.

draxxxeus
  • 1,503
  • 1
  • 11
  • 14
  • Just to a quick look and noticed that you defined `child_key`s but not the associated `parent_key`s. This may not be the problem, but I seem to remember fixing some issues I had with DM by doing this. When I get some more time I'll take a better look and add an actual answer, unless of course you've already figured it out... – Gus Shortz Jun 06 '13 at 01:34

1 Answers1

0

Try this:

   SELECT 
      *
   FROM 
      `contacts_groups` 
   INNER JOIN `contacts_group_owners` 
      ON `contacts_groups`.`id` = `contacts_group_owners`.`owned_group_id` 
   INNER JOIN `contacts_users` 
      ON `contacts_group_owners`.`owner_id` = `contacts_users`.`id` 
   WHERE 
      `contacts_group_owners`.`owned_group_id` = 1 
Stephan
  • 8,000
  • 3
  • 36
  • 42
  • I am using DataMapper and I would not prefer writing mysql queries. I want to know if there is anything wrong with the models. BTW, the output should be testgroup1 and testgroup2 but your query is returning only testgroup1. – draxxxeus May 13 '13 at 09:45
  • @draxxxeus i not quite familiar with python so i just wanted to see if i can help you with the query and yes it returns only testgroup1 since you have the condition ``contacts_group_owners`.`owned_group_id` = 1` but it also returns testuser1 and testuser2 – Stephan May 13 '13 at 10:01
  • Well, firstly it's ruby and secondly, I haven't written the MySQL query. DataMapper is an ORM which generates the queries. Anyway, thanks for your effort. – draxxxeus May 13 '13 at 10:07
  • Sorry about the mistake , if that query was generated by an ORM then for sure the mapping isn't done right , sorry that i'm not able to help you more – Stephan May 13 '13 at 10:10