Question

I'm looking for some pointers on how to keep a CoreData model in sync with a MongoDB. I'm leveraging the ObjCMongoDB framework and I can create objects in core data as follows:

coreDataObj = [BSONDecoder decodeManagedObjectWithClass:[Hostname class]
                                                context:[self managedObjectContext]
                                                   data:[bson_host dataValue]];

Unfortunately when you re-import the MongoDB a copy of the same objects is made and stored.

I'm not sure if I am using the ObjCMongoDB framework incorrectly or if I need to be using SyncServices to import data into my coredata model?

Can someone guide me or provide an example?

Was it helpful?

Solution

ObjCMongoDB (of which I'm author) performs deserialization to Core Data, but, at present, not deduplication or syncing. It treats BSON documents as simple ordered dictionaries, without a sense of an identification attribute. In particular, it treats _id like any other key.

You can get the behavior you want but you'll need to implement it yourself.

The easiest way would be to implement -awakeAfterUsingCoder: or -awakeAfterUsingBSONDecoder: – doesn't matter which – in your NSManagedObject subclass. The decoder will automatically invoke these.

self will be the new, deserialized object. Run a fetch request to look for an existing entry which self duplicates. If you find one, apply the properties to the existing object, delete the new object from the context, and return the existing entry. If you don't find one, simply return self.

You can use -dictionaryWithValuesForKeys: and -setValuesForKeysWithDictionary: to accomplish this, and I usually get a list of keys with a method like this:

+ (NSArray *) persistentKeysForEntity:(NSEntityDescription *) entity {
    NSMutableArray *result = [NSMutableArray array];
    for (NSPropertyDescription *pdesc in [entity properties]) {
        if ([pdesc isTransient]) continue;
        [result addObject:pdesc.name];
    }
    return [result copy];
}

Added: If you don't need to exclude transient attributes, you can apply the values with one line:

[target setValuesForKeysWithDictionary:[self dictionaryWithValuesForKeys:self.entity.attributesByName.allKeys]];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top