Mongoose / MongoDB用户通知方案建议

时间:2012-04-01 15:19:02

标签: mongodb mongoose

我想知道用户/通知类型的最佳方案是什么,如下所示:

  • 您有多个用户。
  • 您可能有多个通知可能针对单个用户,某些用户或所有用户。
  • 您需要在存储空间中输入通知“读取”条目,以了解用户是否已阅读通知。

选项一

嵌入式通知方案

Notifications = new Schema ( {
    message : String,
    date : { type : Date, default: Date.now() }
    read : { type: Boolean, default : false }
});

User = new Schema( {
    username : String,
    name : String,
    notifications : [Notifications]
});

优点:

  • 显示数据非常容易,因为调用User.find()会将通知显示为数组对象。

缺点:

  • 为每个用户创建通知时,需要对每个嵌入的通知执行.push
  • 每个用户的多个通知条目(数据库中的多个数据)
  • 巨型嵌入式文档(我读过有关< 4MB限制的内容)
  • 由于它是嵌入式文档 - (mongoose DocumentArray),您无法搜索或跳过。每次访问用户时都会加载每个通知。

选项二

填充(DBRef like)对象

Notification = new Schema ({
    message : String,
    date : { type : Date, default : Date.now() }
});

UserNotification = new Schema ({
    user : { type : Schema.ObjectId, ref : 'User' },
    notification : { type : Schema.ObjectId, ref : 'Notification' },
    read : { type : Boolean, default : false }
});

User = new Schema( {
    username : String,
    name : String,
    notifications : [ { type : Schema.ObjectID, ref : 'UserNotification' } ]
});

优点:

  • 最适合查询
  • 没有重复数据
  • 支持大量通知

缺点:

  • 您有3个集合,而不是(选项1 只有一个集合)
  • 每次访问该集合时,您都有3个查询。

问题

  1. 您认为这两个方案的最佳方案是什么?
  2. 我错过了某些基本的NoSQL知识吗?
  3. 有人可以提出更好的计划吗?
  4. 先谢谢你,我很抱歉这篇长篇文章,但我想我无法解释它更简单。

2 个答案:

答案 0 :(得分:10)

选项1看起来可能会导致大量过多的文档增长和移动,这会对性能造成影响,因为大多数写入都将转到嵌入式文档(通知)。

选项2我对你的策略并不完全清楚 - 拥有这3个集合似乎是多余的,但如果你已经在通知表中引用了ID,那么还可以通过objectId嵌入一个通知列表。您可以在Notifications表中为用户编制索引,然后在Users表中删除嵌套数组。

(编辑) 这是另一个需要考虑的策略。

三个看起来像这样的集合:

Users:
   _id: objectid
   username : string
   name: string

Notifications:
   _id:  objectid
   to (indexed):   objectid referencing _id in "users" collection
   read: boolean

Global Notifications:
   _id: objectid
   read_by: [objectid referencing _id in users]

对于针对单个用户的通知,请插入该用户的通知。对于多个用户,为每个用户插入一个(或者,您可以将“to”字段设为数组并存储所有收件人的_ids,然后维护已读取所有收件人的所有收件人的另一个列表)。要向所有用户发送通知,请插入Global Notifications集合。当用户读取它时,将其用户的_id添加到read_by字段。 因此,要获取用户的所有未读通知的列表,您需要执行两个查询:一个用于通知,一个用于全局通知。

答案 1 :(得分:0)

//
//  AppDelegate.m
//  myappgames
//
//  Created by Vishal on 9/10/15.
//  Copyright (c) 2015 Vishal. All rights reserved.
//

#import "AppDelegate.h"
#import "UIDevice+Res.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>



@interface AppDelegate ()

@end

@implementation AppDelegate
@synthesize navigationObj;
@synthesize bannerViewAdUnitID,InterstitialAdUnitID;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [[FBSDKApplicationDelegate sharedInstance] application:application
                             didFinishLaunchingWithOptions:launchOptions];
    //--------Admob Ids---------
    bannerViewAdUnitID = @"ca-app-pub-00000";

    //--------InterstitialAd Ids---------
    InterstitialAdUnitID = @"ca-app-pub-00000000";


    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        self.viewcontroller = [[ViewController alloc] initWithNibName:@"ViewController_IPad" bundle:nil];
        navigationObj = [[UINavigationController alloc]initWithRootViewController:self.viewcontroller];
        self.window.rootViewController = navigationObj;
    } else {
        self.viewcontroller = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        navigationObj = [[UINavigationController alloc]initWithRootViewController:self.viewcontroller];
        self.window.rootViewController = navigationObj;
    }
    [self.window makeKeyAndVisible];
    return YES;
}



- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [FBSDKAppEvents activateApp];
}



    - (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
    return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                          openURL:url
                                                sourceApplication:sourceApplication
                                                       annotation:annotation];
}


- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}



- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end