Search code examples
mongodblift

How to use lift-json's class extractor constructor mongo bson array?


I'm use lift-json render a bson string with class extractor, after that, use mongo Document class constructor a document instance with that bson string.

A problem is how about represent $or bson.It seems not a classic json array.

 {"$or": [
      {"username": "administrator"},
      {"phone":"110"},
      {"email":"123@xxx.com"},
      {"pen_name":"lorancechen"}
 ]}

How to use lift class extractor represent this bson array?

Besides, the reason of use string between app and mongo is they are communicate under a simple socket.

UPDATE add a example
extractor a normal array class as follow:

import net.liftweb.json._
import net.liftweb.json.Extraction._

case class Name(name: String)
case class JsonArray(array:List[Name])

object JsonClient extends App {
  implicit val formats = DefaultFormats

  val names = Name("jone01") :: Name("jone02") :: Nil
  val array = JsonArray(names)
  val jsonString = prettyRender(decompose(array))
  println(jsonString)
}

OUTPUT:

{
  "array":[
    {
      "name":"jone01"
    },
    {
      "name":"jone02"
    }
  ]
}

How to represent this

{"$or": [
      {"username": "administrator"},
      {"phone":"110"},
      {"email":"123@xxx.com"},
      {"pen_name":"lorancechen"}
 ]}

every field key (eg, username, phone) of element inner "$or" is not common key name and I haven't find a way to represent it use class template.


Solution

  • I don't get it why your JSON structure is that way, maybe what you want is the following one:

    {
      "$or": [
        {
          "username": "administrator", "phone":"110",  
          "email":"123@xxx.com", "pen_name":"lorancechen"
        },
        {
          "username": "xxx", "phone":"xxx",  
          "email":"xxx", "pen_name":"xxx"
        }
        ...
      ]
    }
    

    Actually Lift provides such tools and the downside is that the implementation is a little bit ugly.

      import net.liftweb.mongodb.{JsonObjectMeta, JsonObject}
    
      // the trait here is for unifying the type of 
      //four case classes i.e Username, Phone....
      sealed trait PersonField
    
      object Username extends JsonObjectMeta[Username]
      case class Username(username: String) extends JsonObject[Username] 
         with PersonField {
         def meta = Username
      }
    
      case class Phone(phone: String) extends JsonObject[Phone] with PersonField {
         def meta = Phone
      }
      object Phone extends JsonObjectMeta[Phone]
    
      case class Email(email: String) extends JsonObject[Email] with PersonField {
         def meta = Email
      }
      object Email extends JsonObjectMeta[Email]
    
      case class PenName(pen_name: String) extends JsonObject[PenName] 
         with PersonField {
         def meta = PenName
      }
      object PenName extends JsonObjectMeta[PenName]
    
      case class Output(`$or`: List[PersonField]) extends JsonObject[Output] {
        def meta = Output
      }
    
      object Output extends JsonObjectMeta[Output]
    
    
      object JsonClient extends App {
    
         val username = Username("administrator")
         val phone = Phone("110")
         val email = Email("123@xxx.com")
         val penName = PenName("lorancechen")
         val outPut = Output(username :: phone :: email :: penName :: Nil)
    
         import net.liftweb.json._
         implicit val formats = DefaultFormats
    
         import net.liftweb.json.{JsonAST, Printer}
         val result = Printer.pretty(JsonAST.render(outPut.asJObject))
    
         /*
            {
              "$or":[{
                "username":"administrator"
              },{
                "phone":"110"
              },{
                "email":"123@xxx.com"
              },{
                "pen_name":"lorancechen"
              }]
            }
    
         */
         println(result)
      }
    

    Anyway, hope it helps.