MongoDB - 一对多关系

时间:2017-01-09 11:06:50

标签: mongodb

我正在使用MongoDB,我有以下结构:

websites

seo_keywords

因此,文档如下所示:

{
    "_id" : ObjectId("58503934034b512b419a6eab"),
    "website" : "https://www.google.com",
    "keywords" : [ 
        "testing", 
        "search", 
        "engine"
    ]
} 

在帖子中包含一个集合:

{
    "_id" : ObjectId("5873656cf632580b98e889b4"),
    "position" : 2,
    "keyword" : "search",
    "found_url" : "https://google.com/"
}

我希望能够将这两者链接在一起,这样我就可以查询seo_keywords所有google网站的{ "_id" : ObjectId("5873656cf632580b98e889b4"), "position" : 2, "keyword" : "search", "found_url" : "https://google.com/", "website" : [ "_id" : ObjectId("58503934034b512b419a6eab"), "website" : "https://www.google.com", "keywords" : [ "testing", "search", "engine" ] ] }

最好/最有效的方法是什么?我已经读过以下方法可以达到这个目的:

package com.cooltechworks.creditcarddesign;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.text.InputFilter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;


import com.cooltechworks.creditcarddesign.pager.AddCardTkn;
import com.cooltechworks.creditcarddesign.pager.CardCVVFragment;
import com.cooltechworks.creditcarddesign.pager.CardFragmentAdapter;
import com.cooltechworks.creditcarddesign.pager.CardFragmentAdapter.ICardEntryCompleteListener;

import com.stripe.android.Stripe;
import com.stripe.android.TokenCallback;
import com.stripe.android.model.Card;
import com.stripe.android.model.Token;

import static com.cooltechworks.creditcarddesign.CreditCardUtils.EXTRA_CARD_CVV;
import static com.cooltechworks.creditcarddesign.CreditCardUtils.EXTRA_CARD_EXPIRY;
import static com.cooltechworks.creditcarddesign.CreditCardUtils.EXTRA_CARD_HOLDER_NAME;
import static com.cooltechworks.creditcarddesign.CreditCardUtils.*;


public class CardEditFragment extends Fragment {


    //public static final String STRIPE_PUBLISHABLE_KEY = "pk_live_xxxxxxxxxxx";
    public static String STRIPE_PUBLISHABLE_KEY = "pk_test_xxxxxxxxxxx";

    private TextView tvNext;
    private TextView tvPrevious;


    int mLastPageSelected = 0;
    private CreditCardView mCreditCardView;

    private ViewPager pager;

    private String mCardNumber;
    private String mCVV;
    private String mCardHolderName;
    private String mExpiry;

    private String mPostcode;

    private CardFragmentAdapter mCardAdapter;

    private AddCardTkn tknHandlerDelegate;
    private View editCardView;

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final View editCardView = inflater.inflate(R.layout.activity_card_edit, container, false);

        this.editCardView = editCardView;


        tknHandlerDelegate = getActivity().getIntent().getParcelableExtra("interface");

        tvNext = (TextView) editCardView.findViewById(R.id.next);
        tvPrevious = (TextView) editCardView.findViewById(R.id.previous);

        tvNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                pager = (ViewPager) editCardView.findViewById(R.id.card_field_container_pager);

                int max = pager.getAdapter().getCount();

                if (pager.getCurrentItem() == max - 1) {
                    // if last card.
                    onDoneTapped();
                } else {
                    showNext();
                }
            }
        });
        tvPrevious.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showPrevious();
            }
        });

        setKeyboardVisibility(true);
        mCreditCardView = (CreditCardView) editCardView.findViewById(R.id.credit_card_view);


        if (savedInstanceState != null) {
            checkParams(savedInstanceState);
        } else {
            checkParams(getActivity().getIntent().getExtras());
        }

        loadPager();

        return editCardView;

    }

    private void checkParams(Bundle bundle) {


        if (bundle == null) {
            return;
        }
        mCardHolderName = bundle.getString(EXTRA_CARD_HOLDER_NAME);
        mCVV = bundle.getString(EXTRA_CARD_CVV);
        mExpiry = bundle.getString(EXTRA_CARD_EXPIRY);
        mCardNumber = bundle.getString(EXTRA_CARD_NUMBER);


        mCreditCardView.setCVV(mCVV);
        mCreditCardView.setCardHolderName(mCardHolderName);
        mCreditCardView.setCardExpiry(mExpiry);
        mCreditCardView.setCardNumber(mCardNumber);


        if (mCardAdapter != null) {
            mCardAdapter.notifyDataSetChanged();
        }
    }

    public void refreshNextButton() {

        ViewPager pager = (ViewPager) editCardView.findViewById(R.id.card_field_container_pager);

        int max = pager.getAdapter().getCount();

        int text = R.string.next;

        if (pager.getCurrentItem() == max - 1) {
            text = R.string.done;
        }

        ((TextView) editCardView.findViewById(R.id.next)).setText(text);
    }

    public void loadPager() {

        ViewPager pager;
        pager = (ViewPager) editCardView.findViewById(R.id.card_field_container_pager);
        if (pager != null) {
            pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }

                @Override
                public void onPageSelected(int position) {
                    CardCVVFragment cvvFrag = (CardCVVFragment) mCardAdapter.getItem(2);
                    int maxLength = 3;

                    if (mCardNumber.length() == 15) {
                        cvvFrag.isAmex = true;
                        maxLength = 4;
                    } else {

                        cvvFrag.isAmex = false;
                    }

                    InputFilter[] fArray = new InputFilter[1];
                    fArray[0] = new InputFilter.LengthFilter(maxLength);
                    cvvFrag.getCardCVVView().setFilters(fArray);
                    mCardAdapter.focus(position);

                    if (position == 2 && !cvvFrag.isAmex) {
                        mCreditCardView.showBack();
                    } else if ((position == 1 && mLastPageSelected == 2) || (position == 3 && !cvvFrag.isAmex)) {
                        mCreditCardView.showFront();
                    }

                    mLastPageSelected = position;

                    refreshNextButton();

                }

                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
            pager.setOffscreenPageLimit(5);
        }
        mCardAdapter = new CardFragmentAdapter(getActivity().getSupportFragmentManager(), getActivity().getIntent().getExtras());
        mCardAdapter.setOnCardEntryCompleteListener(new ICardEntryCompleteListener() {
            @Override
            public void onCardEntryComplete(int currentIndex) {

                showNext();
            }

            @Override
            public void onCardEntryEdit(int currentIndex, String entryValue) {
                switch (currentIndex) {
                    case 0:
                        mCardNumber = entryValue.replace(CreditCardUtils.SPACE_SEPERATOR, "");
                        mCreditCardView.setCardNumber(mCardNumber);
                        break;
                    case 1:
                        mExpiry = entryValue;
                        mCreditCardView.setCardExpiry(entryValue);
                        break;
                    case 2:
                        mCVV = entryValue;
                        mCreditCardView.setCVV(entryValue);
                        break;
                    case 3:
                        mCardHolderName = entryValue;
                        mCreditCardView.setCardHolderName(entryValue);
                        break;
                    case 4:
                        mPostcode = entryValue;
                        mCreditCardView.setCardPostcode(entryValue);
                        break;
                }
            }
        });

        pager.setAdapter(mCardAdapter);
    }

    public void onSaveInstanceState(Bundle outState) {

        outState.putString(EXTRA_CARD_CVV, mCVV);
        outState.putString(EXTRA_CARD_HOLDER_NAME, mCardHolderName);
        outState.putString(EXTRA_CARD_EXPIRY, mExpiry);
        outState.putString(EXTRA_CARD_NUMBER, mCardNumber);
        outState.putString(EXTRA_REGISTERED_POSTCODE, mPostcode);


        super.onSaveInstanceState(outState);
    }


    public void showPrevious() {

        final ViewPager pager = (ViewPager) editCardView.findViewById(R.id.card_field_container_pager);
        int currentIndex = pager.getCurrentItem();

        if (currentIndex - 1 >= 0) {
            pager.setCurrentItem(currentIndex - 1);
        }

        refreshNextButton();
    }

    public void showNext() {

        final ViewPager pager = (ViewPager) editCardView.findViewById(R.id.card_field_container_pager);
        CardFragmentAdapter adapter = (CardFragmentAdapter) pager.getAdapter();

        int max = adapter.getCount();
        int currentIndex = pager.getCurrentItem();

        if (currentIndex + 1 < max) {

            pager.setCurrentItem(currentIndex + 1);
        } else {
            // completed the card entry.
            setKeyboardVisibility(false);
        }

        refreshNextButton();
    }

    private void onDoneTapped() {
        if (mCardHolderName == null || mCardHolderName.equals(""))
        {
            handleError("Please enter the cardholders name");
            return;
        }
        if (mPostcode == null || mPostcode.equals(""))
        {
            handleError("Please enter the cardholders postcode");
            return;
        }
        if (mExpiry == null || mExpiry.length() != 5) {
            handleError("The expiration date that you entered is invalid");
            return;
        }
        String month = mExpiry.substring(0, 2);
        String year = mExpiry.substring(3);

        Card card = new Card(mCardNumber,
                Integer.parseInt(month),
                Integer.parseInt(year),
                mCVV,
                mCardHolderName,
                "",
                "",
                "",
                "",
                mPostcode,
                "",
                "");
        boolean validation = card.validateCard();

        if (validation) {
            startProgress();
            new Stripe().createToken(
                    card,
                    STRIPE_PUBLISHABLE_KEY,
                    new TokenCallback() {
                        public void onSuccess(Token token) {
                            //Send to server
                            Log.d("Stripe Token", token.toString());

                            //For purpose of booking while Not registered yet
                            Bundle appointmentInfo = getActivity().getIntent().getExtras();
                            tknHandlerDelegate.addCard(token.getId(), getActivity(), appointmentInfo);

                        }

                        public void onError(Exception error) {
                            handleError(error.getLocalizedMessage());
                            finishProgress();
                        }
                    });
        } else if (!card.validateNumber()) {
            handleError("The card number that you entered is invalid");
        } else if (!card.validateExpiryDate()) {
            handleError("The expiration date that you entered is invalid");
        } else if (!card.validateCVC()) {
            handleError("The CVC code that you entered is invalid");
        } else {
            handleError("The card details that you entered are invalid");
        }


    }

    private void startProgress() {
        tknHandlerDelegate.showProgress(getActivity());

    }

    private void finishProgress() {
        tknHandlerDelegate.hideProgress(getActivity());
    }

    private void handleError(String error) {

        tknHandlerDelegate.handleError(error, getActivity());
    }

    // from the link above
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);


        // Checks whether a hardware keyboard is available
        if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {

            LinearLayout parent = (LinearLayout) editCardView.findViewById(R.id.parent);
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) parent.getLayoutParams();
            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 0);
            parent.setLayoutParams(layoutParams);

        }
    }

    private void setKeyboardVisibility(boolean visible) {

        final EditText editText = (EditText) editCardView.findViewById(R.id.card_number_field);


        if (!visible) {

            InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
        } else {
            getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        }
    }

}

但这是最有效的方法吗?我可以不使用ID或实际网站将文档链接在一起吗?

1 个答案:

答案 0 :(得分:1)

如果我们的关系密钥在两个集合中都相似,我们可以尝试使用$lookup,因为它提供了MongoDB 3.2+的加入。

db.posts.aggregate([
    {
      $lookup:
        {
          from: "websites",
          localField: "found_url",
          foreignField: "website",
          as: "post_websites"
        }
   }
])