0

Be kind this is my first question on StackOverflow :p. I am hoping its specific enough.

Here is how the project is structured

  1. REST API built using NodeJS and MongoDB (mongoose has been used for modelling the database schemas) with a Express server.
  2. Android app.
  3. Web app using AngularJS

My question is regarding how I should structure synchronisation of data between the Android app and the REST API. The following points bring clarity to the entire scenario -

  • The database model (on the server) is pretty complex with each database model having multiple subdocuments.
  • There are about 6 - 7 models which reference each other.
  • I am currently using Volley to get the data from the remote server.
  • I am also considering adding a SyncAdapter for syncing the data regularly and am not sure as to how to incorporate this with a local database. Should I have a different ContentProvider for every table / model in the database? and how should I handle nested schemas (that are in the remote server) locally?

To summarise my question what I exactly want to know is considering that there will be about 15-20 requests per user per day for about 100,000 users daily, would the best approach be to -

  • Use volley to do all my database work.
  • Use a local database (SQLite) along with a SyncAdapter to keep the data in sync automatically? If this is the case could you recommend some resources to better understand how to integrate a complex database with SyncAdapter.
  • Anything else you suggest for structuring this app.
  • To demonstrate the complexity of the app please have a look at the models below

    This is the user model

    var AddressSchema = new Schema({
        name: String,
        address: String,
        mobile: String,
        pincode: String,
        city: String,
        state: String
    });
    
    var CartSchema = new Schema({
        book: { type: Schema.Types.ObjectId, ref: 'Book' },
        quantity: {
            type: Number,
            default: 1
        },
        dateAdded: Date
    });
    
    var WishlistSchema = new Schema({
        book: { type: Schema.Types.ObjectId, ref: 'Book' },
        dateAdded: Date
    });
    
    var OrderSchema = new Schema({
        orderNumber: String,
        cart: [CartSchema],
        totalAmount: Number,
        deliveryCharge: Number,
        discountAmount: Number,
        address: [AddressSchema],
        date: Date,
        deliveryDate: Date,
        deliveryStatus: String
    });
    
    var SellOrderSchema = new Schema({
        orderNumber: String,
        bookDetails: [{
            isbn: String,
            title: String,
            quantity: {
                type: Number,
                default: 1
            }
        }],
        address: [AddressSchema],
        date: {
            type: Date,
            default: Date.now()
        }
    });
    
    var ReceivedOrdersSchema = new Schema({
        orderNumber: String,
        bookDetails: [{
            book: { type: Schema.Types.ObjectId, ref: 'Book' },
            quantity: Number,
            price: Number
        }],
        dueDate: Date,
        status: {
            type: String,
            default: 'Pending'
        }
    });
    
    var CouponSchema = new Schema({
        coupon: [{ type: Schema.Types.ObjectId, ref: 'Coupon' }],
        used: Number,
        totalDiscount: Number
    });
    
    var UserSchema = new Schema({
        name: String,
        email: { type: String, lowercase: true },
        role: {
            type: String,
            default: 'user'
        },
        hashedPassword: String,
        provider: String,
        salt: String,
        facebook: {},
        twitter: {},
        google: {},
        github: {},
        usedCoupons: [CouponSchema],
        cart: [CartSchema],
        wishlist: [WishlistSchema],
        orders: [OrderSchema],
        sellOrders: [SellOrderSchema],
        addresses: [AddressSchema],
        booksToSell: [{ type: Schema.Types.ObjectId, ref: 'Book' }],
        receivedOrders: [ReceivedOrdersSchema]
    });
    

    This is the books model

    var BookSchema = new Schema({
      _creator : {type: Schema.Types.ObjectId, ref: 'User'},
      title: String,
      subtitle: String,
      author: String,
      language: String,
      pages: Number,
      publisher: String,
      publishedDate: String,
      isbn10: String,
      isbn13: String, 
      description: String,
      dimensions: {
        height: String,
        width: String,
        thickness: String
      },
      category: String,
      rating: String,
      bookType: String,
      imageLinks: {
        extraLarge: String,
        large: String,
        medium: String,
        small: String,
        smallThumbnail: String,
        thumbnail: String,
        uploaded: String   
      },
      uploadedImageLink: String,
      supplierData: {
        mrp: Number,
        supplierPrice: Number,
        quantity: Number
      },
      pricing: {
        salesPrice: Number,
        deliveryCharge: Number
      },
      dateAdded: Date,
      isFeatured: Boolean,
      isBestseller: Boolean
    });
    

    There are 5-6 other such models that are dependent on each other

    Sreehari
    • 5,621
    • 2
    • 25
    • 59

    1 Answers1

    0

    Static Data

    Data like your UserTable is mostly static so you can store it in SQLite (or even Shared Preferences) for fast local data access. Also the stored data about books(title, author etc) is pretty much static (I don't think the author changes that often) so caching it in a SQLite is easy and straight-forward.

    Dynamic Data

    Caching dynamic data? Hard, useless but if you have to use Volley, it helps you a lot. Volley caches your responses using HTTP tags like Expire and Last-Modified. Your app will send a HTTP Request with an If-Modified-Since tag that contains a timestamp. If the data from your server has changed since that timestamp you will receive a normal response. Otherwise, you will receive a HTTP 304 Not Modified and you can use your old cached data. In both cases you app will save the current timestamp and use that next time. All of this is handled by Volley and hidden from you, but is useful to know. You will have to figure out how to handle this on the server side. If you don't want your server to handle to many connections, you could show your user cached data first and implement a Pull to Request gesture that would send a request.

    Offline Access

    Volley gives you an abstraction layer for times when you app isn't able to access the internet, but you should add a clear visual indicator for the user so they know that whatever you have showed them could have changed in the meantime.

    All in all, you should divide your data based on how often it changes and according to that employ different strategies. Specify an expiration period or date to volley when you know it.

    Felix Mada
    • 36
    • 1
    • 3
    • Do you think it would be wise to use SyncAdapter along with volley. The other tables are very much dynamic? – TanveerSehgal Mar 31 '16 at 14:05
    • use SyncAdapters for infrequent requests(in the background, like check for updates in the user's book list or in a "Recommended books" list)and Volley for runtime requests. Also, try to make one big request instead of a lot of small ones when using SyncAdapter. – Felix Mada Mar 31 '16 at 16:13